/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- *//* vim: set ts=8 sts=2 et sw=2 tw=80: *//* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */#include"nsGlobalWindow.h"#include<algorithm>#include"mozilla/MemoryReporting.h"// Local Includes#include"Navigator.h"#include"nsContentSecurityManager.h"#include"nsScreen.h"#include"nsHistory.h"#include"nsDOMNavigationTiming.h"#include"nsIDOMStorageManager.h"#include"mozilla/dom/LocalStorage.h"#include"mozilla/dom/Storage.h"#include"mozilla/dom/IdleRequest.h"#include"mozilla/dom/Performance.h"#include"mozilla/dom/StorageEvent.h"#include"mozilla/dom/StorageEventBinding.h"#include"mozilla/dom/Timeout.h"#include"mozilla/dom/TimeoutHandler.h"#include"mozilla/dom/TimeoutManager.h"#include"mozilla/IntegerPrintfMacros.h"#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)#include"mozilla/dom/WindowOrientationObserver.h"#endif#include"nsDOMOfflineResourceList.h"#include"nsError.h"#include"nsIIdleService.h"#include"nsISizeOfEventTarget.h"#include"nsDOMJSUtils.h"#include"nsArrayUtils.h"#include"nsIDOMWindowCollection.h"#include"nsDOMWindowList.h"#include"mozilla/dom/WakeLock.h"#include"mozilla/dom/power/PowerManagerService.h"#include"nsIDocShellTreeOwner.h"#include"nsIInterfaceRequestorUtils.h"#include"nsIPermissionManager.h"#include"nsIScriptContext.h"#include"nsIScriptTimeoutHandler.h"#include"nsITimeoutHandler.h"#include"nsIController.h"#include"nsScriptNameSpaceManager.h"#include"nsISlowScriptDebug.h"#include"nsWindowMemoryReporter.h"#include"WindowNamedPropertiesHandler.h"#include"nsFrameSelection.h"#include"nsNetUtil.h"#include"nsVariant.h"#include"nsPrintfCString.h"#include"mozilla/intl/LocaleService.h"// Helper Classes#include"nsJSUtils.h"#include"jsapi.h" // for JSAutoRequest#include"jswrapper.h"#include"nsCharSeparatedTokenizer.h"#include"nsReadableUtils.h"#include"nsDOMClassInfo.h"#include"nsJSEnvironment.h"#include"mozilla/dom/ScriptSettings.h"#include"mozilla/Preferences.h"#include"mozilla/Likely.h"#include"mozilla/Sprintf.h"#include"mozilla/Unused.h"// Other Classes#include"mozilla/dom/BarProps.h"#include"nsContentCID.h"#include"nsLayoutStatics.h"#include"nsCCUncollectableMarker.h"#include"mozilla/dom/workers/Workers.h"#include"mozilla/dom/ToJSValue.h"#include"nsJSPrincipals.h"#include"mozilla/Attributes.h"#include"mozilla/Debug.h"#include"mozilla/EventListenerManager.h"#include"mozilla/EventStates.h"#include"mozilla/MouseEvents.h"#include"mozilla/ProcessHangMonitor.h"#include"mozilla/ThrottledEventQueue.h"#include"AudioChannelService.h"#include"nsAboutProtocolUtils.h"#include"nsCharTraits.h" // NS_IS_HIGH/LOW_SURROGATE#include"PostMessageEvent.h"#include"mozilla/dom/DocGroup.h"#include"mozilla/dom/TabGroup.h"// Interfaces Needed#include"nsIFrame.h"#include"nsCanvasFrame.h"#include"nsIWidget.h"#include"nsIWidgetListener.h"#include"nsIBaseWindow.h"#include"nsIDeviceSensors.h"#include"nsIContent.h"#include"nsIDocShell.h"#include"nsIDocCharset.h"#include"nsIDocument.h"#include"Crypto.h"#include"nsIDOMDocument.h"#include"nsIDOMElement.h"#include"nsIDOMEvent.h"#include"nsIDOMOfflineResourceList.h"#include"nsDOMString.h"#include"nsIEmbeddingSiteWindow.h"#include"nsThreadUtils.h"#include"nsILoadContext.h"#include"nsIPresShell.h"#include"nsIScrollableFrame.h"#include"nsView.h"#include"nsViewManager.h"#include"nsISelectionController.h"#include"nsISelection.h"#include"nsIPrompt.h"#include"nsIPromptService.h"#include"nsIPromptFactory.h"#include"nsIWritablePropertyBag2.h"#include"nsIWebNavigation.h"#include"nsIWebBrowserChrome.h"#include"nsIWebBrowserFind.h" // For window.find()#include"nsIWindowMediator.h" // For window.find()#include"nsComputedDOMStyle.h"#include"nsDOMCID.h"#include"nsDOMWindowUtils.h"#include"nsIWindowWatcher.h"#include"nsPIWindowWatcher.h"#include"nsIContentViewer.h"#include"nsIScriptError.h"#include"nsIControllers.h"#include"nsIControllerContext.h"#include"nsGlobalWindowCommands.h"#include"nsQueryObject.h"#include"nsContentUtils.h"#include"nsCSSProps.h"#include"nsIDOMFileList.h"#include"nsIURIFixup.h"#ifndef DEBUG#include"nsIAppStartup.h"#include"nsToolkitCompsCID.h"#endif#include"nsCDefaultURIFixup.h"#include"mozilla/EventDispatcher.h"#include"mozilla/EventStateManager.h"#include"nsIObserverService.h"#include"nsFocusManager.h"#include"nsIXULWindow.h"#include"nsITimedChannel.h"#include"nsServiceManagerUtils.h"#ifdef MOZ_XUL#include"nsIDOMXULControlElement.h"#include"nsMenuPopupFrame.h"#endif#include"mozilla/dom/CustomEvent.h"#include"nsIJARChannel.h"#include"nsIScreenManager.h"#include"nsIEffectiveTLDService.h"#include"xpcprivate.h"#ifdef NS_PRINTING#include"nsIPrintSettings.h"#include"nsIPrintSettingsService.h"#include"nsIWebBrowserPrint.h"#endif#include"nsWindowRoot.h"#include"nsNetCID.h"#include"nsIArray.h"// XXX An unfortunate dependency exists here (two XUL files).#include"nsIDOMXULDocument.h"#include"nsIDOMXULCommandDispatcher.h"#include"nsBindingManager.h"#include"nsXBLService.h"// used for popup blocking, needs to be converted to something// belonging to the back-end like nsIContentPolicy#include"nsIPopupWindowManager.h"#include"nsIDragService.h"#include"mozilla/dom/Element.h"#include"mozilla/dom/Selection.h"#include"nsFrameLoader.h"#include"nsISupportsPrimitives.h"#include"nsXPCOMCID.h"#include"mozilla/Logging.h"#include"prenv.h"#include"mozilla/dom/IDBFactory.h"#include"mozilla/dom/MessageChannel.h"#include"mozilla/dom/Promise.h"#include"mozilla/dom/Gamepad.h"#include"mozilla/dom/GamepadManager.h"#include"gfxVR.h"#include"mozilla/dom/VRDisplay.h"#include"mozilla/dom/VRDisplayEvent.h"#include"mozilla/dom/VRDisplayEventBinding.h"#include"mozilla/dom/VREventObserver.h"#include"nsRefreshDriver.h"#include"Layers.h"#include"mozilla/AddonPathService.h"#include"mozilla/BasePrincipal.h"#include"mozilla/Services.h"#include"mozilla/Telemetry.h"#include"mozilla/dom/Location.h"#include"nsHTMLDocument.h"#include"nsWrapperCacheInlines.h"#include"mozilla/DOMEventTargetHelper.h"#include"prrng.h"#include"nsSandboxFlags.h"#include"TimeChangeObserver.h"#include"mozilla/dom/AudioContext.h"#include"mozilla/dom/BrowserElementDictionariesBinding.h"#include"mozilla/dom/cache/CacheStorage.h"#include"mozilla/dom/Console.h"#include"mozilla/dom/Fetch.h"#include"mozilla/dom/FunctionBinding.h"#include"mozilla/dom/HashChangeEvent.h"#ifdef ENABLE_INTL_API#include"mozilla/dom/IntlUtils.h"#endif#include"mozilla/dom/MozSelfSupportBinding.h"#include"mozilla/dom/PopStateEvent.h"#include"mozilla/dom/PopupBlockedEvent.h"#include"mozilla/dom/PrimitiveConversions.h"#include"mozilla/dom/WindowBinding.h"#include"nsITabChild.h"#include"mozilla/dom/MediaQueryList.h"#include"mozilla/dom/ScriptSettings.h"#include"mozilla/dom/NavigatorBinding.h"#include"mozilla/dom/ImageBitmap.h"#include"mozilla/dom/ImageBitmapBinding.h"#include"mozilla/dom/ServiceWorkerRegistration.h"#include"mozilla/dom/U2F.h"#include"mozilla/dom/WebIDLGlobalNameHash.h"#include"mozilla/dom/Worklet.h"#ifdef HAVE_SIDEBAR#include"mozilla/dom/ExternalBinding.h"#endif#ifdef MOZ_WEBSPEECH#include"mozilla/dom/SpeechSynthesis.h"#endif#ifdef MOZ_B2G#include"nsPISocketTransportService.h"#endif// Apple system headers seem to have a check() macro. <sigh>#ifdef checkclassnsIScriptTimeoutHandler;#undef check#endif // check#include"AccessCheck.h"#ifdef ANDROID#include<android/log.h>#endif#ifdef XP_WIN#include<process.h>#define getpid _getpid#else#include<unistd.h> // for getpid()#endifstaticconstcharkStorageEnabled[]="dom.storage.enabled";usingnamespacemozilla;usingnamespacemozilla::dom;usingnamespacemozilla::dom::ipc;usingmozilla::BasePrincipal;usingmozilla::OriginAttributes;usingmozilla::TimeStamp;usingmozilla::TimeDuration;usingmozilla::dom::cache::CacheStorage;staticLazyLogModulegDOMLeakPRLog("DOMLeak");nsGlobalWindow::WindowByIdTable*nsGlobalWindow::sWindowsById=nullptr;boolnsGlobalWindow::sWarnedAboutWindowInternal=false;boolnsGlobalWindow::sIdleObserversAPIFuzzTimeDisabled=false;staticint32_tgRefCnt=0;staticint32_tgOpenPopupSpamCount=0;staticPopupControlStategPopupControlState=openAbused;staticboolgMouseDown=false;staticboolgDragServiceDisabled=false;staticFILE*gDumpFile=nullptr;staticuint32_tgSerialCounter=0;#ifdef DEBUG_jstint32_tgTimeoutCnt=0;#endif#if defined(DEBUG_bryner) || defined(DEBUG_chb)#define DEBUG_PAGE_CACHE#endif#define DOM_TOUCH_LISTENER_ADDED "dom-touch-listener-added"// The interval at which we execute idle callbacksstaticuint32_tgThrottledIdlePeriodLength;#define DEFAULT_THROTTLED_IDLE_PERIOD_LENGTH 10000#define FORWARD_TO_OUTER(method, args, err_rval) \ PR_BEGIN_MACRO \ if (IsInnerWindow()) { \ nsGlobalWindow *outer = GetOuterWindowInternal(); \ if (!AsInner()->HasActiveDocument()) { \ NS_WARNING(outer ? \ "Inner window does not have active document." : \ "No outer window available!"); \ return err_rval; \ } \ return outer->method args; \ } \ PR_END_MACRO#define FORWARD_TO_OUTER_OR_THROW(method, args, errorresult, err_rval) \ PR_BEGIN_MACRO \ MOZ_RELEASE_ASSERT(IsInnerWindow()); \ nsGlobalWindow *outer = GetOuterWindowInternal(); \ if (MOZ_LIKELY(AsInner()->HasActiveDocument())) { \ return outer->method args; \ } \ if (!outer) { \ NS_WARNING("No outer window available!"); \ errorresult.Throw(NS_ERROR_NOT_INITIALIZED); \ } else { \ errorresult.Throw(NS_ERROR_XPC_SECURITY_MANAGER_VETO); \ } \ return err_rval; \ PR_END_MACRO#define FORWARD_TO_OUTER_VOID(method, args) \ PR_BEGIN_MACRO \ if (IsInnerWindow()) { \ nsGlobalWindow *outer = GetOuterWindowInternal(); \ if (!AsInner()->HasActiveDocument()) { \ NS_WARNING(outer ? \ "Inner window does not have active document." : \ "No outer window available!"); \ return; \ } \ outer->method args; \ return; \ } \ PR_END_MACRO#define FORWARD_TO_OUTER_CHROME(method, args, err_rval) \ PR_BEGIN_MACRO \ if (IsInnerWindow()) { \ nsGlobalWindow *outer = GetOuterWindowInternal(); \ if (!AsInner()->HasActiveDocument()) { \ NS_WARNING(outer ? \ "Inner window does not have active document." : \ "No outer window available!"); \ return err_rval; \ } \ return ((nsGlobalChromeWindow *)outer)->method args; \ } \ PR_END_MACRO#define FORWARD_TO_INNER_CHROME(method, args, err_rval) \ PR_BEGIN_MACRO \ if (IsOuterWindow()) { \ if (!mInnerWindow) { \ NS_WARNING("No inner window available!"); \ return err_rval; \ } \ return ((nsGlobalChromeWindow *)nsGlobalWindow::Cast(mInnerWindow))->method args; \ } \ PR_END_MACRO#define FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(method, args, err_rval) \ PR_BEGIN_MACRO \ if (IsInnerWindow()) { \ nsGlobalWindow *outer = GetOuterWindowInternal(); \ if (!AsInner()->HasActiveDocument()) { \ NS_WARNING(outer ? \ "Inner window does not have active document." : \ "No outer window available!"); \ return err_rval; \ } \ return ((nsGlobalModalWindow *)outer)->method args; \ } \ PR_END_MACRO#define FORWARD_TO_INNER(method, args, err_rval) \ PR_BEGIN_MACRO \ if (IsOuterWindow()) { \ if (!mInnerWindow) { \ NS_WARNING("No inner window available!"); \ return err_rval; \ } \ return GetCurrentInnerWindowInternal()->method args; \ } \ PR_END_MACRO#define FORWARD_TO_INNER_MODAL_CONTENT_WINDOW(method, args, err_rval) \ PR_BEGIN_MACRO \ if (IsOuterWindow()) { \ if (!mInnerWindow) { \ NS_WARNING("No inner window available!"); \ return err_rval; \ } \ return ((nsGlobalModalWindow*)GetCurrentInnerWindowInternal())->method args; \ } \ PR_END_MACRO#define FORWARD_TO_INNER_VOID(method, args) \ PR_BEGIN_MACRO \ if (IsOuterWindow()) { \ if (!mInnerWindow) { \ NS_WARNING("No inner window available!"); \ return; \ } \ GetCurrentInnerWindowInternal()->method args; \ return; \ } \ PR_END_MACRO// Same as FORWARD_TO_INNER, but this will create a fresh inner if an// inner doesn't already exists.#define FORWARD_TO_INNER_CREATE(method, args, err_rval) \ PR_BEGIN_MACRO \ if (IsOuterWindow()) { \ if (!mInnerWindow) { \ if (mIsClosed) { \ return err_rval; \ } \ nsCOMPtr<nsIDocument> kungFuDeathGrip = GetDoc(); \ ::mozilla::Unused << kungFuDeathGrip; \ if (!mInnerWindow) { \ return err_rval; \ } \ } \ return GetCurrentInnerWindowInternal()->method args; \ } \ PR_END_MACRO// CIDsstaticNS_DEFINE_CID(kXULControllersCID,NS_XULCONTROLLERS_CID);#define NETWORK_UPLOAD_EVENT_NAME NS_LITERAL_STRING("moznetworkupload")#define NETWORK_DOWNLOAD_EVENT_NAME NS_LITERAL_STRING("moznetworkdownload")/** * An indirect observer object that means we don't have to implement nsIObserver * on nsGlobalWindow, where any script could see it. */classnsGlobalWindowObserverfinal:publicnsIObserver,publicnsIInterfaceRequestor{public:explicitnsGlobalWindowObserver(nsGlobalWindow*aWindow):mWindow(aWindow){}NS_DECL_ISUPPORTSNS_IMETHODObserve(nsISupports*aSubject,constchar*aTopic,constchar16_t*aData)override{if(!mWindow)returnNS_OK;returnmWindow->Observe(aSubject,aTopic,aData);}voidForget(){mWindow=nullptr;}NS_IMETHODGetInterface(constnsIID&aIID,void**aResult)override{if(mWindow&&aIID.Equals(NS_GET_IID(nsIDOMWindow))&&mWindow){returnmWindow->QueryInterface(aIID,aResult);}returnNS_NOINTERFACE;}private:~nsGlobalWindowObserver()=default;// This reference is non-owning and safe because it's cleared by// nsGlobalWindow::CleanUp().nsGlobalWindow*MOZ_NON_OWNING_REFmWindow;};NS_IMPL_ISUPPORTS(nsGlobalWindowObserver,nsIObserver,nsIInterfaceRequestor)staticalready_AddRefed<nsIVariant>CreateVoidVariant(){RefPtr<nsVariantCC>writable=newnsVariantCC();writable->SetAsVoid();returnwritable.forget();}nsresultDialogValueHolder::Get(nsIPrincipal*aSubject,nsIVariant**aResult){nsCOMPtr<nsIVariant>result;if(aSubject->SubsumesConsideringDomain(mOrigin)){result=mValue;}else{result=CreateVoidVariant();}result.forget(aResult);returnNS_OK;}voidDialogValueHolder::Get(JSContext*aCx,JS::Handle<JSObject*>aScope,nsIPrincipal*aSubject,JS::MutableHandle<JS::Value>aResult,mozilla::ErrorResult&aError){if(aSubject->Subsumes(mOrigin)){aError=nsContentUtils::XPConnect()->VariantToJS(aCx,aScope,mValue,aResult);}else{aResult.setUndefined();}}classIdleRequestExecutor;classIdleRequestExecutorTimeoutHandlerfinal:publicTimeoutHandler{public:explicitIdleRequestExecutorTimeoutHandler(IdleRequestExecutor*aExecutor):mExecutor(aExecutor){}NS_DECL_ISUPPORTS_INHERITEDNS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IdleRequestExecutorTimeoutHandler,TimeoutHandler)nsresultCall()override;private:~IdleRequestExecutorTimeoutHandler()override{}RefPtr<IdleRequestExecutor>mExecutor;};NS_IMPL_CYCLE_COLLECTION_INHERITED(IdleRequestExecutorTimeoutHandler,TimeoutHandler,mExecutor)NS_IMPL_ADDREF_INHERITED(IdleRequestExecutorTimeoutHandler,TimeoutHandler)NS_IMPL_RELEASE_INHERITED(IdleRequestExecutorTimeoutHandler,TimeoutHandler)NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IdleRequestExecutorTimeoutHandler)NS_INTERFACE_MAP_END_INHERITING(TimeoutHandler)classIdleRequestExecutorfinal:publicnsIRunnable,publicnsICancelableRunnable,publicnsINamed,publicnsIIdleRunnable{public:explicitIdleRequestExecutor(nsGlobalWindow*aWindow):mDispatched(false),mDeadline(TimeStamp::Now()),mWindow(aWindow){MOZ_DIAGNOSTIC_ASSERT(mWindow);MOZ_DIAGNOSTIC_ASSERT(mWindow->IsInnerWindow());mIdlePeriodLimit={mDeadline,mWindow->LastIdleRequestHandle()};mDelayedExecutorDispatcher=newIdleRequestExecutorTimeoutHandler(this);}NS_DECL_CYCLE_COLLECTING_ISUPPORTSNS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(IdleRequestExecutor,nsIRunnable)NS_DECL_NSIRUNNABLENS_DECL_NSINAMEDnsresultCancel()override;voidSetDeadline(TimeStampaDeadline)override;boolIsCancelled()const{return!mWindow||mWindow->AsInner()->InnerObjectsFreed();}// Checks if aRequest shouldn't execute in the current idle period// since it has been queued from a chained call to// requestIdleCallback from within a running idle callback.boolIneligibleForCurrentIdlePeriod(IdleRequest*aRequest)const{returnaRequest->Handle()>=mIdlePeriodLimit.mLastRequestIdInIdlePeriod&&TimeStamp::Now()<=mIdlePeriodLimit.mEndOfIdlePeriod;}voidMaybeUpdateIdlePeriodLimit();// Maybe dispatch the IdleRequestExecutor. MabyeDispatch will// schedule a delayed dispatch if the associated window is in the// background or if given a time to wait until dispatching.voidMaybeDispatch(TimeStampaDelayUntil=TimeStamp());voidScheduleDispatch();private:structIdlePeriodLimit{TimeStampmEndOfIdlePeriod;uint32_tmLastRequestIdInIdlePeriod;};voidDelayedDispatch(uint32_taDelay);~IdleRequestExecutor()override{}boolmDispatched;TimeStampmDeadline;IdlePeriodLimitmIdlePeriodLimit;RefPtr<nsGlobalWindow>mWindow;// The timeout handler responsible for dispatching this executor in// the case of immediate dispatch to the idle queue isn't// desirable. This is used if we've dispatched all idle callbacks// that are allowed to run in the current idle period, or if the// associated window is currently in the background.nsCOMPtr<nsITimeoutHandler>mDelayedExecutorDispatcher;// If not Nothing() then this value is the handle to the currently// scheduled delayed executor dispatcher. This is needed to be able// to cancel the timeout handler in case of the executor being// cancelled.Maybe<int32_t>mDelayedExecutorHandle;};NS_IMPL_CYCLE_COLLECTION_CLASS(IdleRequestExecutor)NS_IMPL_CYCLE_COLLECTING_ADDREF(IdleRequestExecutor)NS_IMPL_CYCLE_COLLECTING_RELEASE(IdleRequestExecutor)NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IdleRequestExecutor)NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)NS_IMPL_CYCLE_COLLECTION_UNLINK(mDelayedExecutorDispatcher)NS_IMPL_CYCLE_COLLECTION_UNLINK_ENDNS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IdleRequestExecutor)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDelayedExecutorDispatcher)NS_IMPL_CYCLE_COLLECTION_TRAVERSE_ENDNS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IdleRequestExecutor)NS_INTERFACE_MAP_ENTRY(nsIRunnable)NS_INTERFACE_MAP_ENTRY(nsICancelableRunnable)NS_INTERFACE_MAP_ENTRY(nsINamed)NS_INTERFACE_MAP_ENTRY(nsIIdleRunnable)NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports,nsIRunnable)NS_INTERFACE_MAP_ENDNS_IMETHODIMPIdleRequestExecutor::GetName(nsACString&aName){aName.AssignASCII("IdleRequestExecutor");returnNS_OK;}NS_IMETHODIMPIdleRequestExecutor::SetName(constchar*aName){returnNS_ERROR_NOT_IMPLEMENTED;}NS_IMETHODIMPIdleRequestExecutor::Run(){MOZ_ASSERT(NS_IsMainThread());mDispatched=false;if(mWindow){returnmWindow->ExecuteIdleRequest(mDeadline);}returnNS_OK;}nsresultIdleRequestExecutor::Cancel(){MOZ_ASSERT(NS_IsMainThread());if(mDelayedExecutorHandle&&mWindow){mWindow->AsInner()->TimeoutManager().ClearTimeout(mDelayedExecutorHandle.value(),Timeout::Reason::eIdleCallbackTimeout);}mWindow=nullptr;returnNS_OK;}voidIdleRequestExecutor::SetDeadline(TimeStampaDeadline){MOZ_ASSERT(NS_IsMainThread());if(!mWindow){return;}mDeadline=aDeadline;}voidIdleRequestExecutor::MaybeUpdateIdlePeriodLimit(){if(TimeStamp::Now()>mIdlePeriodLimit.mEndOfIdlePeriod){mIdlePeriodLimit={mDeadline,mWindow->LastIdleRequestHandle()};}}voidIdleRequestExecutor::MaybeDispatch(TimeStampaDelayUntil){// If we've already dispatched the executor we don't want to do it// again. Also, if we've called IdleRequestExecutor::Cancel mWindow// will be null, which indicates that we shouldn't dispatch this// executor either.if(mDispatched||IsCancelled()){return;}mDispatched=true;nsPIDOMWindowOuter*outer=mWindow->GetOuterWindow();if(outer&&outer->AsOuter()->IsBackground()){// Set a timeout handler with a timeout of 0 ms to throttle idle// callback requests coming from a backround window using// background timeout throttling.DelayedDispatch(0);return;}TimeStampnow=TimeStamp::Now();if(!aDelayUntil||aDelayUntil<now){ScheduleDispatch();return;}TimeDurationdelay=aDelayUntil-now;DelayedDispatch(static_cast<uint32_t>(delay.ToMilliseconds()));}voidIdleRequestExecutor::ScheduleDispatch(){MOZ_ASSERT(mWindow);mDelayedExecutorHandle=Nothing();RefPtr<IdleRequestExecutor>request=this;NS_IdleDispatchToCurrentThread(request.forget());}voidIdleRequestExecutor::DelayedDispatch(uint32_taDelay){MOZ_ASSERT(mWindow);MOZ_ASSERT(mDelayedExecutorHandle.isNothing());int32_thandle;mWindow->AsInner()->TimeoutManager().SetTimeout(mDelayedExecutorDispatcher,aDelay,false,Timeout::Reason::eIdleCallbackTimeout,&handle);mDelayedExecutorHandle=Some(handle);}nsresultIdleRequestExecutorTimeoutHandler::Call(){if(!mExecutor->IsCancelled()){mExecutor->ScheduleDispatch();}returnNS_OK;}voidnsGlobalWindow::ScheduleIdleRequestDispatch(){AssertIsOnMainThread();if(!mIdleRequestExecutor){mIdleRequestExecutor=newIdleRequestExecutor(this);}mIdleRequestExecutor->MaybeDispatch();}voidnsGlobalWindow::SuspendIdleRequests(){if(mIdleRequestExecutor){mIdleRequestExecutor->Cancel();mIdleRequestExecutor=nullptr;}}voidnsGlobalWindow::ResumeIdleRequests(){MOZ_ASSERT(!mIdleRequestExecutor);ScheduleIdleRequestDispatch();}voidnsGlobalWindow::InsertIdleCallback(IdleRequest*aRequest){AssertIsOnMainThread();mIdleRequestCallbacks.insertBack(aRequest);aRequest->AddRef();}voidnsGlobalWindow::RemoveIdleCallback(mozilla::dom::IdleRequest*aRequest){AssertIsOnMainThread();if(aRequest->HasTimeout()){mTimeoutManager->ClearTimeout(aRequest->GetTimeoutHandle(),Timeout::Reason::eIdleCallbackTimeout);}aRequest->removeFrom(mIdleRequestCallbacks);aRequest->Release();}nsresultnsGlobalWindow::RunIdleRequest(IdleRequest*aRequest,DOMHighResTimeStampaDeadline,boolaDidTimeout){AssertIsOnMainThread();RefPtr<IdleRequest>request(aRequest);RemoveIdleCallback(request);returnrequest->IdleRun(AsInner(),aDeadline,aDidTimeout);}nsresultnsGlobalWindow::ExecuteIdleRequest(TimeStampaDeadline){AssertIsOnMainThread();RefPtr<IdleRequest>request=mIdleRequestCallbacks.getFirst();if(!request){// There are no more idle requests, so stop scheduling idle// request callbacks.returnNS_OK;}// If the request that we're trying to execute has been queued// during the current idle period, then dispatch it again at the end// of the idle period.if(mIdleRequestExecutor->IneligibleForCurrentIdlePeriod(request)){mIdleRequestExecutor->MaybeDispatch(aDeadline);returnNS_OK;}DOMHighResTimeStampdeadline=0.0;if(Performance*perf=GetPerformance()){deadline=perf->GetDOMTiming()->TimeStampToDOMHighRes(aDeadline);}mIdleRequestExecutor->MaybeUpdateIdlePeriodLimit();nsresultresult=RunIdleRequest(request,deadline,false);// Running the idle callback could've suspended the window, in which// case mIdleRequestExecutor will be null.if(mIdleRequestExecutor){mIdleRequestExecutor->MaybeDispatch();}returnresult;}classIdleRequestTimeoutHandlerfinal:publicTimeoutHandler{public:IdleRequestTimeoutHandler(JSContext*aCx,IdleRequest*aIdleRequest,nsPIDOMWindowInner*aWindow):TimeoutHandler(aCx),mIdleRequest(aIdleRequest),mWindow(aWindow){}NS_DECL_ISUPPORTS_INHERITEDNS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IdleRequestTimeoutHandler,TimeoutHandler)nsresultCall()override{returnnsGlobalWindow::Cast(mWindow)->RunIdleRequest(mIdleRequest,0.0,true);}private:~IdleRequestTimeoutHandler()override{}RefPtr<IdleRequest>mIdleRequest;nsCOMPtr<nsPIDOMWindowInner>mWindow;};NS_IMPL_CYCLE_COLLECTION_INHERITED(IdleRequestTimeoutHandler,TimeoutHandler,mIdleRequest,mWindow)NS_IMPL_ADDREF_INHERITED(IdleRequestTimeoutHandler,TimeoutHandler)NS_IMPL_RELEASE_INHERITED(IdleRequestTimeoutHandler,TimeoutHandler)NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IdleRequestTimeoutHandler)NS_INTERFACE_MAP_END_INHERITING(TimeoutHandler)uint32_tnsGlobalWindow::RequestIdleCallback(JSContext*aCx,IdleRequestCallback&aCallback,constIdleRequestOptions&aOptions,ErrorResult&aError){MOZ_RELEASE_ASSERT(IsInnerWindow());AssertIsOnMainThread();uint32_thandle=mIdleRequestCallbackCounter++;RefPtr<IdleRequest>request=newIdleRequest(&aCallback,handle);if(aOptions.mTimeout.WasPassed()){int32_ttimeoutHandle;nsCOMPtr<nsITimeoutHandler>handler(newIdleRequestTimeoutHandler(aCx,request,AsInner()));nsresultrv=mTimeoutManager->SetTimeout(handler,aOptions.mTimeout.Value(),false,Timeout::Reason::eIdleCallbackTimeout,&timeoutHandle);if(NS_WARN_IF(NS_FAILED(rv))){return0;}request->SetTimeoutHandle(timeoutHandle);}// mIdleRequestCallbacks now owns requestInsertIdleCallback(request);if(!IsSuspended()){ScheduleIdleRequestDispatch();}returnhandle;}voidnsGlobalWindow::CancelIdleCallback(uint32_taHandle){MOZ_RELEASE_ASSERT(IsInnerWindow());for(IdleRequest*r:mIdleRequestCallbacks){if(r->Handle()==aHandle){RemoveIdleCallback(r);break;}}}voidnsGlobalWindow::DisableIdleCallbackRequests(){if(mIdleRequestExecutor){mIdleRequestExecutor->Cancel();mIdleRequestExecutor=nullptr;}while(!mIdleRequestCallbacks.isEmpty()){RefPtr<IdleRequest>request=mIdleRequestCallbacks.getFirst();RemoveIdleCallback(request);}}boolnsGlobalWindow::IsBackgroundInternal()const{return!mOuterWindow||mOuterWindow->IsBackground();}namespacemozilla{namespacedom{externuint64_tNextWindowID();}// namespace dom}// namespace mozillatemplate<classT>nsPIDOMWindow<T>::nsPIDOMWindow(nsPIDOMWindowOuter*aOuterWindow):mFrameElement(nullptr),mDocShell(nullptr),mModalStateDepth(0),mMutationBits(0),mIsDocumentLoaded(false),mIsHandlingResizeEvent(false),mIsInnerWindow(aOuterWindow!=nullptr),mMayHavePaintEventListener(false),mMayHaveTouchEventListener(false),mMayHaveSelectionChangeEventListener(false),mMayHaveMouseEnterLeaveEventListener(false),mMayHavePointerEnterLeaveEventListener(false),mInnerObjectsFreed(false),mIsModalContentWindow(false),mIsActive(false),mIsBackground(false),mMediaSuspend(Preferences::GetBool("media.block-autoplay-until-in-foreground",true)?nsISuspendedTypes::SUSPENDED_BLOCK:nsISuspendedTypes::NONE_SUSPENDED),mAudioMuted(false),mAudioVolume(1.0),mAudioCaptured(false),mDesktopModeViewport(false),mIsRootOuterWindow(false),mInnerWindow(nullptr),mOuterWindow(aOuterWindow),// Make sure no actual window ends up with mWindowID == 0mWindowID(NextWindowID()),mHasNotifiedGlobalCreated(false),mMarkedCCGeneration(0),mServiceWorkersTestingEnabled(false),mLargeAllocStatus(LargeAllocStatus::NONE),mHasTriedToCacheTopInnerWindow(false),mNumOfIndexedDBDatabases(0){if(aOuterWindow){mTimeoutManager=MakeUnique<mozilla::dom::TimeoutManager>(*nsGlobalWindow::Cast(AsInner()));}}template<classT>nsPIDOMWindow<T>::~nsPIDOMWindow(){}/* static */nsPIDOMWindowOuter*nsPIDOMWindowOuter::GetFromCurrentInner(nsPIDOMWindowInner*aInner){if(!aInner){returnnullptr;}nsPIDOMWindowOuter*outer=aInner->GetOuterWindow();if(!outer||outer->GetCurrentInnerWindow()!=aInner){returnnullptr;}returnouter;}// DialogValueHolder CC goop.NS_IMPL_CYCLE_COLLECTION(DialogValueHolder,mValue)NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DialogValueHolder)NS_INTERFACE_MAP_ENTRY(nsISupports)NS_INTERFACE_MAP_ENDNS_IMPL_CYCLE_COLLECTING_ADDREF(DialogValueHolder)NS_IMPL_CYCLE_COLLECTING_RELEASE(DialogValueHolder)//*****************************************************************************// nsOuterWindowProxy: Outer Window Proxy//*****************************************************************************classnsOuterWindowProxy:publicjs::Wrapper{public:constexprnsOuterWindowProxy():js::Wrapper(0){}boolfinalizeInBackground(constJS::Value&priv)constoverride{returnfalse;}// Standard internal methodsboolgetOwnPropertyDescriptor(JSContext*cx,JS::Handle<JSObject*>proxy,JS::Handle<jsid>id,JS::MutableHandle<JS::PropertyDescriptor>desc)constoverride;booldefineProperty(JSContext*cx,JS::Handle<JSObject*>proxy,JS::Handle<jsid>id,JS::Handle<JS::PropertyDescriptor>desc,JS::ObjectOpResult&result)constoverride;boolownPropertyKeys(JSContext*cx,JS::Handle<JSObject*>proxy,JS::AutoIdVector&props)constoverride;booldelete_(JSContext*cx,JS::Handle<JSObject*>proxy,JS::Handle<jsid>id,JS::ObjectOpResult&result)constoverride;boolgetPrototypeIfOrdinary(JSContext*cx,JS::Handle<JSObject*>proxy,bool*isOrdinary,JS::MutableHandle<JSObject*>protop)constoverride;JSObject*enumerate(JSContext*cx,JS::Handle<JSObject*>proxy)constoverride;boolpreventExtensions(JSContext*cx,JS::Handle<JSObject*>proxy,JS::ObjectOpResult&result)constoverride;boolisExtensible(JSContext*cx,JS::Handle<JSObject*>proxy,bool*extensible)constoverride;boolhas(JSContext*cx,JS::Handle<JSObject*>proxy,JS::Handle<jsid>id,bool*bp)constoverride;boolget(JSContext*cx,JS::Handle<JSObject*>proxy,JS::Handle<JS::Value>receiver,JS::Handle<jsid>id,JS::MutableHandle<JS::Value>vp)constoverride;boolset(JSContext*cx,JS::Handle<JSObject*>proxy,JS::Handle<jsid>id,JS::Handle<JS::Value>v,JS::Handle<JS::Value>receiver,JS::ObjectOpResult&result)constoverride;// SpiderMonkey extensionsboolgetPropertyDescriptor(JSContext*cx,JS::Handle<JSObject*>proxy,JS::Handle<jsid>id,JS::MutableHandle<JS::PropertyDescriptor>desc)constoverride;boolhasOwn(JSContext*cx,JS::Handle<JSObject*>proxy,JS::Handle<jsid>id,bool*bp)constoverride;boolgetOwnEnumerablePropertyKeys(JSContext*cx,JS::Handle<JSObject*>proxy,JS::AutoIdVector&props)constoverride;constchar*className(JSContext*cx,JS::Handle<JSObject*>wrapper)constoverride;voidfinalize(JSFreeOp*fop,JSObject*proxy)constoverride;boolisCallable(JSObject*obj)constoverride{returnfalse;}boolisConstructor(JSObject*obj)constoverride{returnfalse;}boolwatch(JSContext*cx,JS::Handle<JSObject*>proxy,JS::Handle<jsid>id,JS::Handle<JSObject*>callable)constoverride;boolunwatch(JSContext*cx,JS::Handle<JSObject*>proxy,JS::Handle<jsid>id)constoverride;staticvoidObjectMoved(JSObject*obj,constJSObject*old);staticconstnsOuterWindowProxysingleton;protected:staticnsGlobalWindow*GetOuterWindow(JSObject*proxy){nsGlobalWindow*outerWindow=nsGlobalWindow::FromSupports(static_cast<nsISupports*>(js::GetProxyReservedSlot(proxy,0).toPrivate()));MOZ_ASSERT_IF(outerWindow,outerWindow->IsOuterWindow());returnouterWindow;}// False return value means we threw an exception. True return value// but false "found" means we didn't have a subframe at that index.boolGetSubframeWindow(JSContext*cx,JS::Handle<JSObject*>proxy,JS::Handle<jsid>id,JS::MutableHandle<JS::Value>vp,bool&found)const;// Returns a non-null window only if id is an index and we have a// window at that index.already_AddRefed<nsPIDOMWindowOuter>GetSubframeWindow(JSContext*cx,JS::Handle<JSObject*>proxy,JS::Handle<jsid>id)const;boolAppendIndexedPropertyNames(JSContext*cx,JSObject*proxy,JS::AutoIdVector&props)const;};staticconstjs::ClassExtensionOuterWindowProxyClassExtension=PROXY_MAKE_EXT(nsOuterWindowProxy::ObjectMoved);// Give OuterWindowProxyClass 2 reserved slots, like the other wrappers, so// JSObject::swap can swap it with CrossCompartmentWrappers without requiring// malloc.constjs::ClassOuterWindowProxyClass=PROXY_CLASS_WITH_EXT("Proxy",JSCLASS_HAS_RESERVED_SLOTS(2),/* additional class flags */&OuterWindowProxyClassExtension);constchar*nsOuterWindowProxy::className(JSContext*cx,JS::Handle<JSObject*>proxy)const{MOZ_ASSERT(js::IsProxy(proxy));return"Window";}voidnsOuterWindowProxy::finalize(JSFreeOp*fop,JSObject*proxy)const{nsGlobalWindow*outerWindow=GetOuterWindow(proxy);if(outerWindow){outerWindow->ClearWrapper(proxy);// Ideally we would use OnFinalize here, but it's possible that// EnsureScriptEnvironment will later be called on the window, and we don't// want to create a new script object in that case. Therefore, we need to// write a non-null value that will reliably crash when dereferenced.outerWindow->PoisonOuterWindowProxy(proxy);}}boolnsOuterWindowProxy::getPropertyDescriptor(JSContext*cx,JS::Handle<JSObject*>proxy,JS::Handle<jsid>id,JS::MutableHandle<JS::PropertyDescriptor>desc)const{// The only thing we can do differently from js::Wrapper is shadow stuff with// our indexed properties, so we can just try getOwnPropertyDescriptor and if// that gives us nothing call on through to js::Wrapper.desc.object().set(nullptr);if(!getOwnPropertyDescriptor(cx,proxy,id,desc)){returnfalse;}if(desc.object()){returntrue;}returnjs::Wrapper::getPropertyDescriptor(cx,proxy,id,desc);}boolnsOuterWindowProxy::getOwnPropertyDescriptor(JSContext*cx,JS::Handle<JSObject*>proxy,JS::Handle<jsid>id,JS::MutableHandle<JS::PropertyDescriptor>desc)const{boolfound;if(!GetSubframeWindow(cx,proxy,id,desc.value(),found)){returnfalse;}if(found){FillPropertyDescriptor(desc,proxy,true);returntrue;}// else fall through to js::Wrapperreturnjs::Wrapper::getOwnPropertyDescriptor(cx,proxy,id,desc);}boolnsOuterWindowProxy::defineProperty(JSContext*cx,JS::Handle<JSObject*>proxy,JS::Handle<jsid>id,JS::Handle<JS::PropertyDescriptor>desc,JS::ObjectOpResult&result)const{if(IsArrayIndex(GetArrayIndexFromId(cx,id))){// Spec says to Reject whether this is a supported index or not,// since we have no indexed setter or indexed creator. It is up// to the caller to decide whether to throw a TypeError.returnresult.failCantDefineWindowElement();}returnjs::Wrapper::defineProperty(cx,proxy,id,desc,result);}boolnsOuterWindowProxy::ownPropertyKeys(JSContext*cx,JS::Handle<JSObject*>proxy,JS::AutoIdVector&props)const{// Just our indexed stuff followed by our "normal" own property names.if(!AppendIndexedPropertyNames(cx,proxy,props)){returnfalse;}JS::AutoIdVectorinnerProps(cx);if(!js::Wrapper::ownPropertyKeys(cx,proxy,innerProps)){returnfalse;}returnjs::AppendUnique(cx,props,innerProps);}boolnsOuterWindowProxy::delete_(JSContext*cx,JS::Handle<JSObject*>proxy,JS::Handle<jsid>id,JS::ObjectOpResult&result)const{if(nsCOMPtr<nsPIDOMWindowOuter>frame=GetSubframeWindow(cx,proxy,id)){// Fail (which means throw if strict, else return false).returnresult.failCantDeleteWindowElement();}if(IsArrayIndex(GetArrayIndexFromId(cx,id))){// Indexed, but not supported. Spec says return true.returnresult.succeed();}returnjs::Wrapper::delete_(cx,proxy,id,result);}boolnsOuterWindowProxy::getPrototypeIfOrdinary(JSContext*cx,JS::Handle<JSObject*>proxy,bool*isOrdinary,JS::MutableHandle<JSObject*>protop)const{// Window's [[GetPrototypeOf]] trap isn't the ordinary definition://// https://html.spec.whatwg.org/multipage/browsers.html#windowproxy-getprototypeof//// We nonetheless can implement it with a static [[Prototype]], because// wrapper-class handlers (particularly, XOW in FilteringWrapper.cpp) supply// all non-ordinary behavior.//// But from a spec point of view, it's the exact same object in both cases --// only the observer's changed. So this getPrototypeIfOrdinary trap on the// non-wrapper object *must* report non-ordinary, even if static [[Prototype]]// usually means ordinary.*isOrdinary=false;returntrue;}boolnsOuterWindowProxy::preventExtensions(JSContext*cx,JS::Handle<JSObject*>proxy,JS::ObjectOpResult&result)const{// If [[Extensible]] could be false, then navigating a window could navigate// to a window that's [[Extensible]] after being at one that wasn't: an// invariant violation. So never change a window's extensibility.returnresult.failCantPreventExtensions();}boolnsOuterWindowProxy::isExtensible(JSContext*cx,JS::Handle<JSObject*>proxy,bool*extensible)const{// See above.*extensible=true;returntrue;}boolnsOuterWindowProxy::has(JSContext*cx,JS::Handle<JSObject*>proxy,JS::Handle<jsid>id,bool*bp)const{if(nsCOMPtr<nsPIDOMWindowOuter>frame=GetSubframeWindow(cx,proxy,id)){*bp=true;returntrue;}returnjs::Wrapper::has(cx,proxy,id,bp);}boolnsOuterWindowProxy::hasOwn(JSContext*cx,JS::Handle<JSObject*>proxy,JS::Handle<jsid>id,bool*bp)const{if(nsCOMPtr<nsPIDOMWindowOuter>frame=GetSubframeWindow(cx,proxy,id)){*bp=true;returntrue;}returnjs::Wrapper::hasOwn(cx,proxy,id,bp);}boolnsOuterWindowProxy::get(JSContext*cx,JS::Handle<JSObject*>proxy,JS::Handle<JS::Value>receiver,JS::Handle<jsid>id,JS::MutableHandle<JS::Value>vp)const{if(id==nsDOMClassInfo::sWrappedJSObject_id&&xpc::AccessCheck::isChrome(js::GetContextCompartment(cx))){vp.set(JS::ObjectValue(*proxy));returntrue;}boolfound;if(!GetSubframeWindow(cx,proxy,id,vp,found)){returnfalse;}if(found){returntrue;}// Else fall through to js::Wrapperreturnjs::Wrapper::get(cx,proxy,receiver,id,vp);}boolnsOuterWindowProxy::set(JSContext*cx,JS::Handle<JSObject*>proxy,JS::Handle<jsid>id,JS::Handle<JS::Value>v,JS::Handle<JS::Value>receiver,JS::ObjectOpResult&result)const{if(IsArrayIndex(GetArrayIndexFromId(cx,id))){// Reject the set. It's up to the caller to decide whether to throw a// TypeError. If the caller is strict mode JS code, it'll throw.returnresult.failReadOnly();}returnjs::Wrapper::set(cx,proxy,id,v,receiver,result);}boolnsOuterWindowProxy::getOwnEnumerablePropertyKeys(JSContext*cx,JS::Handle<JSObject*>proxy,JS::AutoIdVector&props)const{// Like ownPropertyKeys, our indexed stuff followed by our "normal" enumerable// own property names.//// Note that this does not match current spec per// https://github.com/whatwg/html/issues/2753 but as that issue says I believe// the spec is wrong.if(!AppendIndexedPropertyNames(cx,proxy,props)){returnfalse;}JS::AutoIdVectorinnerProps(cx);if(!js::Wrapper::getOwnEnumerablePropertyKeys(cx,proxy,innerProps)){returnfalse;}returnjs::AppendUnique(cx,props,innerProps);}JSObject*nsOuterWindowProxy::enumerate(JSContext*cx,JS::Handle<JSObject*>proxy)const{// BaseProxyHandler::enumerate seems to do what we want here: fall// back on the property names returned from js::GetPropertyKeys()returnjs::BaseProxyHandler::enumerate(cx,proxy);}boolnsOuterWindowProxy::GetSubframeWindow(JSContext*cx,JS::Handle<JSObject*>proxy,JS::Handle<jsid>id,JS::MutableHandle<JS::Value>vp,bool&found)const{nsCOMPtr<nsPIDOMWindowOuter>frame=GetSubframeWindow(cx,proxy,id);if(!frame){found=false;returntrue;}found=true;// Just return the window's globalnsGlobalWindow*global=nsGlobalWindow::Cast(frame);frame->EnsureInnerWindow();JSObject*obj=global->FastGetGlobalJSObject();// This null check fixes a hard-to-reproduce crash that occurs when we// get here when we're mid-call to nsDocShell::Destroy. See bug 640904// comment 105.if(MOZ_UNLIKELY(!obj)){returnxpc::Throw(cx,NS_ERROR_FAILURE);}JS::ExposeObjectToActiveJS(obj);vp.setObject(*obj);returnJS_WrapValue(cx,vp);}already_AddRefed<nsPIDOMWindowOuter>nsOuterWindowProxy::GetSubframeWindow(JSContext*cx,JS::Handle<JSObject*>proxy,JS::Handle<jsid>id)const{uint32_tindex=GetArrayIndexFromId(cx,id);if(!IsArrayIndex(index)){returnnullptr;}nsGlobalWindow*win=GetOuterWindow(proxy);MOZ_ASSERT(win->IsOuterWindow());returnwin->IndexedGetterOuter(index);}boolnsOuterWindowProxy::AppendIndexedPropertyNames(JSContext*cx,JSObject*proxy,JS::AutoIdVector&props)const{uint32_tlength=GetOuterWindow(proxy)->Length();MOZ_ASSERT(int32_t(length)>=0);if(!props.reserve(props.length()+length)){returnfalse;}for(int32_ti=0;i<int32_t(length);++i){if(!props.append(INT_TO_JSID(i))){returnfalse;}}returntrue;}boolnsOuterWindowProxy::watch(JSContext*cx,JS::Handle<JSObject*>proxy,JS::Handle<jsid>id,JS::Handle<JSObject*>callable)const{returnjs::WatchGuts(cx,proxy,id,callable);}boolnsOuterWindowProxy::unwatch(JSContext*cx,JS::Handle<JSObject*>proxy,JS::Handle<jsid>id)const{returnjs::UnwatchGuts(cx,proxy,id);}voidnsOuterWindowProxy::ObjectMoved(JSObject*obj,constJSObject*old){nsGlobalWindow*outerWindow=GetOuterWindow(obj);if(outerWindow){outerWindow->UpdateWrapper(obj,old);}}constnsOuterWindowProxynsOuterWindowProxy::singleton;classnsChromeOuterWindowProxy:publicnsOuterWindowProxy{public:constexprnsChromeOuterWindowProxy():nsOuterWindowProxy(){}constchar*className(JSContext*cx,JS::Handle<JSObject*>wrapper)constoverride;staticconstnsChromeOuterWindowProxysingleton;};constchar*nsChromeOuterWindowProxy::className(JSContext*cx,JS::Handle<JSObject*>proxy)const{MOZ_ASSERT(js::IsProxy(proxy));return"ChromeWindow";}constnsChromeOuterWindowProxynsChromeOuterWindowProxy::singleton;staticJSObject*NewOuterWindowProxy(JSContext*cx,JS::Handle<JSObject*>global,boolisChrome){JSAutoCompartmentac(cx,global);MOZ_ASSERT(js::GetGlobalForObjectCrossCompartment(global)==global);js::WrapperOptionsoptions;options.setClass(&OuterWindowProxyClass);options.setSingleton(true);JSObject*obj=js::Wrapper::New(cx,global,isChrome?&nsChromeOuterWindowProxy::singleton:&nsOuterWindowProxy::singleton,options);MOZ_ASSERT_IF(obj,js::IsWindowProxy(obj));returnobj;}//*****************************************************************************//*** nsGlobalWindow: Object Management//*****************************************************************************nsGlobalWindow::nsGlobalWindow(nsGlobalWindow*aOuterWindow):nsPIDOMWindow<nsISupports>(aOuterWindow?aOuterWindow->AsOuter():nullptr),mIdleFuzzFactor(0),mIdleCallbackIndex(-1),mCurrentlyIdle(false),mAddActiveEventFuzzTime(true),mFullScreen(false),mFullscreenMode(false),mIsClosed(false),mInClose(false),mHavePendingClose(false),mHadOriginalOpener(false),mOriginalOpenerWasSecureContext(false),mIsPopupSpam(false),mBlockScriptedClosingFlag(false),mWasOffline(false),mHasHadSlowScript(false),mNotifyIdleObserversIdleOnThaw(false),mNotifyIdleObserversActiveOnThaw(false),mCreatingInnerWindow(false),mIsChrome(false),mCleanMessageManager(false),mNeedsFocus(true),mHasFocus(false),mShowFocusRingForContent(false),mFocusByKeyOccurred(false),mHasGamepad(false),mHasVREvents(false),mHasVRDisplayActivateEvents(false),mHasSeenGamepadInput(false),mNotifiedIDDestroyed(false),mAllowScriptsToClose(false),mTopLevelOuterContentWindow(false),mSuspendDepth(0),mFreezeDepth(0),mFocusMethod(0),mSerial(0),mIdleRequestCallbackCounter(1),mIdleRequestExecutor(nullptr),#ifdef DEBUGmSetOpenerWindowCalled(false),#endif#ifdef MOZ_B2GmNetworkUploadObserverEnabled(false),mNetworkDownloadObserverEnabled(false),#endifmCleanedUp(false),mDialogAbuseCount(0),mAreDialogsEnabled(true),#ifdef DEBUGmIsValidatingTabGroup(false),#endifmCanSkipCCGeneration(0),mAutoActivateVRDisplayID(0),mBeforeUnloadListenerCount(0){AssertIsOnMainThread();nsLayoutStatics::AddRef();// Initialize the PRCList (this).PR_INIT_CLIST(this);if(aOuterWindow){// |this| is an inner window, add this inner window to the outer// window list of inners.PR_INSERT_AFTER(this,aOuterWindow);mObserver=newnsGlobalWindowObserver(this);if(mObserver){nsCOMPtr<nsIObserverService>os=mozilla::services::GetObserverService();if(os){// Watch for online/offline status changes so we can fire events. Use// a strong reference.os->AddObserver(mObserver,NS_IOSERVICE_OFFLINE_STATUS_TOPIC,false);// Watch for dom-storage2-changed and dom-private-storage2-changed so we// can fire storage events. Use a strong reference.os->AddObserver(mObserver,"dom-storage2-changed",false);os->AddObserver(mObserver,"dom-private-storage2-changed",false);}Preferences::AddStrongObserver(mObserver,"intl.accept_languages");}}else{// |this| is an outer window. Outer windows start out frozen and// remain frozen until they get an inner window.MOZ_ASSERT(IsFrozen());}if(XRE_IsContentProcess()){nsCOMPtr<nsIDocShell>docShell=GetDocShell();if(docShell){mTabChild=docShell->GetTabChild();}}// We could have failed the first time through trying// to create the entropy collector, so we should// try to get one until we succeed.gRefCnt++;staticboolsFirstTime=true;if(sFirstTime){TimeoutManager::Initialize();Preferences::AddBoolVarCache(&sIdleObserversAPIFuzzTimeDisabled,"dom.idle-observers-api.fuzz_time.disabled",false);Preferences::AddUintVarCache(&gThrottledIdlePeriodLength,"dom.idle_period.throttled_length",DEFAULT_THROTTLED_IDLE_PERIOD_LENGTH);sFirstTime=false;}if(gDumpFile==nullptr){constnsAdoptingCString&fname=Preferences::GetCString("browser.dom.window.dump.file");if(!fname.IsEmpty()){// if this fails to open, Dump() knows to just go to stdout// on null.gDumpFile=fopen(fname,"wb+");}else{gDumpFile=stdout;}}mSerial=++gSerialCounter;#ifdef DEBUGif(!PR_GetEnv("MOZ_QUIET")){printf_stderr("++DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p]\n",gRefCnt,static_cast<void*>(ToCanonicalSupports(this)),getpid(),gSerialCounter,static_cast<void*>(ToCanonicalSupports(aOuterWindow)));}#endifMOZ_LOG(gDOMLeakPRLog,LogLevel::Debug,("DOMWINDOW %p created outer=%p",this,aOuterWindow));NS_ASSERTION(sWindowsById,"Windows hash table must be created!");NS_ASSERTION(!sWindowsById->Get(mWindowID),"This window shouldn't be in the hash table yet!");// We seem to see crashes in release builds because of null |sWindowsById|.if(sWindowsById){sWindowsById->Put(mWindowID,this);}}#ifdef DEBUG/* static */voidnsGlobalWindow::AssertIsOnMainThread(){MOZ_ASSERT(NS_IsMainThread());}#endif // DEBUG/* static */voidnsGlobalWindow::Init(){AssertIsOnMainThread();NS_ASSERTION(gDOMLeakPRLog,"gDOMLeakPRLog should have been initialized!");sWindowsById=newWindowByIdTable();}nsGlobalWindow::~nsGlobalWindow(){AssertIsOnMainThread();DisconnectEventTargetObjects();// We have to check if sWindowsById isn't null because ::Shutdown might have// been called.if(sWindowsById){NS_ASSERTION(sWindowsById->Get(mWindowID),"This window should be in the hash table");sWindowsById->Remove(mWindowID);}--gRefCnt;#ifdef DEBUGif(!PR_GetEnv("MOZ_QUIET")){nsAutoCStringurl;if(mLastOpenedURI){url=mLastOpenedURI->GetSpecOrDefault();// Data URLs can be very long, so truncate to avoid flooding the log.constuint32_tmaxURLLength=1000;if(url.Length()>maxURLLength){url.Truncate(maxURLLength);}}nsGlobalWindow*outer=nsGlobalWindow::Cast(mOuterWindow);printf_stderr("--DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p] [url = %s]\n",gRefCnt,static_cast<void*>(ToCanonicalSupports(this)),getpid(),mSerial,static_cast<void*>(ToCanonicalSupports(outer)),url.get());}#endifMOZ_LOG(gDOMLeakPRLog,LogLevel::Debug,("DOMWINDOW %p destroyed",this));if(IsOuterWindow()){JSObject*proxy=GetWrapperMaybeDead();if(proxy){js::SetProxyReservedSlot(proxy,0,js::PrivateValue(nullptr));}// An outer window is destroyed with inner windows still possibly// alive, iterate through the inner windows and null out their// back pointer to this outer, and pull them out of the list of// inner windows.nsGlobalWindow*w;while((w=(nsGlobalWindow*)PR_LIST_HEAD(this))!=this){PR_REMOVE_AND_INIT_LINK(w);}DropOuterWindowDocs();}else{Telemetry::Accumulate(Telemetry::INNERWINDOWS_WITH_MUTATION_LISTENERS,mMutationBits?1:0);if(mListenerManager){mListenerManager->Disconnect();mListenerManager=nullptr;}// An inner window is destroyed, pull it out of the outer window's// list if inner windows.PR_REMOVE_LINK(this);// If our outer window's inner window is this window, null out the// outer window's reference to this window that's being deleted.nsGlobalWindow*outer=GetOuterWindowInternal();if(outer){outer->MaybeClearInnerWindow(this);}}// We don't have to leave the tab group if we are an inner window.if(mTabGroup&&IsOuterWindow()){mTabGroup->Leave(AsOuter());}// Outer windows are always supposed to call CleanUp before letting themselves// be destroyed. And while CleanUp generally seems to be intended to clean up// outers, we've historically called it for both. Changing this would probably// involve auditing all of the references that inners and outers can have, and// separating the handling into CleanUp() and FreeInnerObjects.if(IsInnerWindow()){CleanUp();}else{MOZ_ASSERT(mCleanedUp);}nsCOMPtr<nsIDeviceSensors>ac=do_GetService(NS_DEVICE_SENSORS_CONTRACTID);if(ac)ac->RemoveWindowAsListener(this);nsLayoutStatics::Release();}voidnsGlobalWindow::AddEventTargetObject(DOMEventTargetHelper*aObject){MOZ_ASSERT(IsInnerWindow());mEventTargetObjects.PutEntry(aObject);}voidnsGlobalWindow::RemoveEventTargetObject(DOMEventTargetHelper*aObject){MOZ_ASSERT(IsInnerWindow());mEventTargetObjects.RemoveEntry(aObject);}voidnsGlobalWindow::DisconnectEventTargetObjects(){for(autoiter=mEventTargetObjects.ConstIter();!iter.Done();iter.Next()){RefPtr<DOMEventTargetHelper>target=iter.Get()->GetKey();target->DisconnectFromOwner();}mEventTargetObjects.Clear();}// staticvoidnsGlobalWindow::ShutDown(){AssertIsOnMainThread();if(gDumpFile&&gDumpFile!=stdout){fclose(gDumpFile);}gDumpFile=nullptr;deletesWindowsById;sWindowsById=nullptr;}// staticvoidnsGlobalWindow::CleanupCachedXBLHandlers(nsGlobalWindow*aWindow){if(aWindow->mCachedXBLPrototypeHandlers&&aWindow->mCachedXBLPrototypeHandlers->Count()>0){aWindow->mCachedXBLPrototypeHandlers->Clear();}}voidnsGlobalWindow::MaybeForgiveSpamCount(){if(IsOuterWindow()&&IsPopupSpamWindow()){SetIsPopupSpamWindow(false);}}voidnsGlobalWindow::SetIsPopupSpamWindow(boolaIsPopupSpam){MOZ_ASSERT(IsOuterWindow());mIsPopupSpam=aIsPopupSpam;if(aIsPopupSpam){++gOpenPopupSpamCount;}else{--gOpenPopupSpamCount;NS_ASSERTION(gOpenPopupSpamCount>=0,"Unbalanced decrement of gOpenPopupSpamCount");}}voidnsGlobalWindow::DropOuterWindowDocs(){MOZ_ASSERT(IsOuterWindow());MOZ_ASSERT_IF(mDoc,!mDoc->EventHandlingSuppressed());mDoc=nullptr;mSuspendedDoc=nullptr;}voidnsGlobalWindow::CleanUp(){// Guarantee idempotence.if(mCleanedUp)return;mCleanedUp=true;StartDying();DisconnectEventTargetObjects();if(mObserver){nsCOMPtr<nsIObserverService>os=mozilla::services::GetObserverService();if(os){os->RemoveObserver(mObserver,NS_IOSERVICE_OFFLINE_STATUS_TOPIC);os->RemoveObserver(mObserver,"dom-storage2-changed");os->RemoveObserver(mObserver,"dom-private-storage2-changed");}#ifdef MOZ_B2GDisableNetworkEvent(eNetworkUpload);DisableNetworkEvent(eNetworkDownload);#endif // MOZ_B2Gif(mIdleService){mIdleService->RemoveIdleObserver(mObserver,MIN_IDLE_NOTIFICATION_TIME_S);}Preferences::RemoveObserver(mObserver,"intl.accept_languages");// Drop its reference to this dying window, in case for some bogus reason// the object stays around.mObserver->Forget();}if(mNavigator){mNavigator->Invalidate();mNavigator=nullptr;}mScreen=nullptr;mMenubar=nullptr;mToolbar=nullptr;mLocationbar=nullptr;mPersonalbar=nullptr;mStatusbar=nullptr;mScrollbars=nullptr;mHistory=nullptr;mCustomElements=nullptr;mFrames=nullptr;mWindowUtils=nullptr;mApplicationCache=nullptr;mIndexedDB=nullptr;mConsole=nullptr;mAudioWorklet=nullptr;mPaintWorklet=nullptr;mExternal=nullptr;mMozSelfSupport=nullptr;mPerformance=nullptr;#ifdef MOZ_WEBSPEECHmSpeechSynthesis=nullptr;#endif#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)mOrientationChangeObserver=nullptr;#endifClearControllers();mOpener=nullptr;// Forces Releaseif(mContext){mContext=nullptr;// Forces Release}mChromeEventHandler=nullptr;// Forces ReleasemParentTarget=nullptr;if(IsOuterWindow()){nsGlobalWindow*inner=GetCurrentInnerWindowInternal();if(inner){inner->CleanUp();}}if(IsInnerWindow()){DisableGamepadUpdates();mHasGamepad=false;DisableVRUpdates();mHasVREvents=false;mHasVRDisplayActivateEvents=false;#ifdef MOZ_B2GDisableTimeChangeNotifications();#endifDisableIdleCallbackRequests();}else{MOZ_ASSERT(!mHasGamepad);MOZ_ASSERT(!mHasVREvents);MOZ_ASSERT(!mHasVRDisplayActivateEvents);}if(mCleanMessageManager){MOZ_ASSERT(mIsChrome,"only chrome should have msg manager cleaned");nsGlobalChromeWindow*asChrome=static_cast<nsGlobalChromeWindow*>(this);if(asChrome->mMessageManager){static_cast<nsFrameMessageManager*>(asChrome->mMessageManager.get())->Disconnect();}}mArguments=nullptr;mDialogArguments=nullptr;CleanupCachedXBLHandlers(this);for(uint32_ti=0;i<mAudioContexts.Length();++i){mAudioContexts[i]->Shutdown();}mAudioContexts.Clear();if(mIdleTimer){mIdleTimer->Cancel();mIdleTimer=nullptr;}mServiceWorkerRegistrationTable.Clear();#ifdef ENABLE_INTL_APImIntlUtils=nullptr;#endif}voidnsGlobalWindow::ClearControllers(){if(mControllers){uint32_tcount;mControllers->GetControllerCount(&count);while(count--){nsCOMPtr<nsIController>controller;mControllers->GetControllerAt(count,getter_AddRefs(controller));nsCOMPtr<nsIControllerContext>context=do_QueryInterface(controller);if(context)context->SetCommandContext(nullptr);}mControllers=nullptr;}}voidnsGlobalWindow::FreeInnerObjects(){NS_ASSERTION(IsInnerWindow(),"Don't free inner objects on an outer window");// Make sure that this is called before we null out the document and// other members that the window destroyed observers could// re-create.NotifyDOMWindowDestroyed(this);if(auto*reporter=nsWindowMemoryReporter::Get()){reporter->ObserveDOMWindowDetached(this);}mInnerObjectsFreed=true;// Kill all of the workers for this window.mozilla::dom::workers::CancelWorkersForWindow(AsInner());if(mTimeoutManager){mTimeoutManager->ClearAllTimeouts();}if(mIdleTimer){mIdleTimer->Cancel();mIdleTimer=nullptr;}mIdleObservers.Clear();DisableIdleCallbackRequests();mChromeEventHandler=nullptr;if(mListenerManager){mListenerManager->Disconnect();mListenerManager=nullptr;}mHistory=nullptr;mCustomElements=nullptr;if(mNavigator){mNavigator->OnNavigation();mNavigator->Invalidate();mNavigator=nullptr;}if(mScreen){mScreen=nullptr;}#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)mOrientationChangeObserver=nullptr;#endifif(mDoc){// Remember the document's principal and URI.mDocumentPrincipal=mDoc->NodePrincipal();mDocumentURI=mDoc->GetDocumentURI();mDocBaseURI=mDoc->GetDocBaseURI();while(mDoc->EventHandlingSuppressed()){mDoc->UnsuppressEventHandlingAndFireEvents(false);}}// Remove our reference to the document and the document principal.mFocusedNode=nullptr;if(mApplicationCache){static_cast<nsDOMOfflineResourceList*>(mApplicationCache.get())->Disconnect();mApplicationCache=nullptr;}mIndexedDB=nullptr;UnlinkHostObjectURIs();NotifyWindowIDDestroyed("inner-window-destroyed");CleanupCachedXBLHandlers(this);for(uint32_ti=0;i<mAudioContexts.Length();++i){mAudioContexts[i]->Shutdown();}mAudioContexts.Clear();DisableGamepadUpdates();mHasGamepad=false;mGamepads.Clear();DisableVRUpdates();mHasVREvents=false;mHasVRDisplayActivateEvents=false;mVRDisplays.Clear();if(mTabChild){while(mBeforeUnloadListenerCount-->0){mTabChild->BeforeUnloadRemoved();}}}//*****************************************************************************// nsGlobalWindow::nsISupports//*****************************************************************************// QueryInterface implementation for nsGlobalWindowNS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsGlobalWindow)NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY// Make sure this matches the cast in nsGlobalWindow::FromWrapper()NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports,nsIDOMEventTarget)NS_INTERFACE_MAP_ENTRY(nsIDOMWindow)if(aIID.Equals(NS_GET_IID(nsIDOMWindowInternal))){foundInterface=static_cast<nsIDOMWindowInternal*>(this);if(!sWarnedAboutWindowInternal){sWarnedAboutWindowInternal=true;nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,NS_LITERAL_CSTRING("Extensions"),mDoc,nsContentUtils::eDOM_PROPERTIES,"nsIDOMWindowInternalWarning");}}elseNS_INTERFACE_MAP_ENTRY(nsIGlobalObject)NS_INTERFACE_MAP_ENTRY(nsIScriptGlobalObject)NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal)NS_INTERFACE_MAP_ENTRY(nsIDOMEventTarget)NS_INTERFACE_MAP_ENTRY(mozilla::dom::EventTarget)if(aIID.Equals(NS_GET_IID(nsPIDOMWindowInner))){foundInterface=AsInner();}elseif(aIID.Equals(NS_GET_IID(mozIDOMWindow))&&IsInnerWindow()){foundInterface=AsInner();}elseif(aIID.Equals(NS_GET_IID(nsPIDOMWindowOuter))){foundInterface=AsOuter();}elseif(aIID.Equals(NS_GET_IID(mozIDOMWindowProxy))&&IsOuterWindow()){foundInterface=AsOuter();}elseNS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)NS_INTERFACE_MAP_ENDNS_IMPL_CYCLE_COLLECTING_ADDREF(nsGlobalWindow)NS_IMPL_CYCLE_COLLECTING_RELEASE(nsGlobalWindow)NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsGlobalWindow)if(tmp->IsBlackForCC(false)){if(nsCCUncollectableMarker::InGeneration(tmp->mCanSkipCCGeneration)){returntrue;}tmp->mCanSkipCCGeneration=nsCCUncollectableMarker::sGeneration;if(tmp->mCachedXBLPrototypeHandlers){for(autoiter=tmp->mCachedXBLPrototypeHandlers->Iter();!iter.Done();iter.Next()){iter.Data().exposeToActiveJS();}}if(EventListenerManager*elm=tmp->GetExistingListenerManager()){elm->MarkForCC();}if(tmp->mTimeoutManager){tmp->mTimeoutManager->UnmarkGrayTimers();}returntrue;}NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_ENDNS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsGlobalWindow)returntmp->IsBlackForCC(true);NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_ENDNS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsGlobalWindow)returntmp->IsBlackForCC(false);NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_ENDinlinevoidImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback&aCallback,IdleObserverHolder&aField,constchar*aName,unsignedaFlags){CycleCollectionNoteChild(aCallback,aField.mIdleObserver.get(),aName,aFlags);}NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalWindow)NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindow)if(MOZ_UNLIKELY(cb.WantDebugInfo())){charname[512];nsAutoCStringuri;if(tmp->mDoc&&tmp->mDoc->GetDocumentURI()){uri=tmp->mDoc->GetDocumentURI()->GetSpecOrDefault();}SprintfLiteral(name,"nsGlobalWindow # %"PRIu64" %s %s",tmp->mWindowID,tmp->IsInnerWindow()?"inner":"outer",uri.get());cb.DescribeRefCountedNode(tmp->mRefCnt.get(),name);}else{NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsGlobalWindow,tmp->mRefCnt.get())}NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContext)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mControllers)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mArguments)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDialogArguments)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mReturnValue)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNavigator)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPerformance)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mServiceWorkerRegistrationTable)#ifdef MOZ_WEBSPEECHNS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSpeechSynthesis)#endifNS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOuterWindow)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTopInnerWindow)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListenerManager)if(tmp->mTimeoutManager){tmp->mTimeoutManager->ForEachUnorderedTimeout([&cb](Timeout*timeout){cb.NoteNativeChild(timeout,NS_CYCLE_COLLECTION_PARTICIPANT(Timeout));});}NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocation)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHistory)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCustomElements)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocalStorage)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSessionStorage)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mApplicationCache)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSuspendedDoc)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIndexedDB)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentPrincipal)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTabChild)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDoc)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleService)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWakeLock)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleRequestExecutor)for(IdleRequest*request:tmp->mIdleRequestCallbacks){cb.NoteNativeChild(request,NS_CYCLE_COLLECTION_PARTICIPANT(IdleRequest));}NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleObservers)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGamepads)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCacheStorage)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVRDisplays)// Traverse stuff from nsPIDOMWindowNS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeEventHandler)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParentTarget)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFrameElement)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFocusedNode)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMenubar)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mToolbar)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocationbar)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPersonalbar)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStatusbar)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScrollbars)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCrypto)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mU2F)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConsole)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAudioWorklet)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPaintWorklet)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mExternal)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMozSelfSupport)#ifdef ENABLE_INTL_APINS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIntlUtils)#endiftmp->TraverseHostObjectURIs(cb);NS_IMPL_CYCLE_COLLECTION_TRAVERSE_ENDNS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindow)nsGlobalWindow::CleanupCachedXBLHandlers(tmp);NS_IMPL_CYCLE_COLLECTION_UNLINK(mContext)NS_IMPL_CYCLE_COLLECTION_UNLINK(mControllers)NS_IMPL_CYCLE_COLLECTION_UNLINK(mArguments)NS_IMPL_CYCLE_COLLECTION_UNLINK(mDialogArguments)NS_IMPL_CYCLE_COLLECTION_UNLINK(mReturnValue)NS_IMPL_CYCLE_COLLECTION_UNLINK(mNavigator)NS_IMPL_CYCLE_COLLECTION_UNLINK(mPerformance)NS_IMPL_CYCLE_COLLECTION_UNLINK(mServiceWorkerRegistrationTable)#ifdef MOZ_WEBSPEECHNS_IMPL_CYCLE_COLLECTION_UNLINK(mSpeechSynthesis)#endifif(tmp->mOuterWindow){nsGlobalWindow::Cast(tmp->mOuterWindow)->MaybeClearInnerWindow(tmp);NS_IMPL_CYCLE_COLLECTION_UNLINK(mOuterWindow)}if(tmp->mListenerManager){tmp->mListenerManager->Disconnect();NS_IMPL_CYCLE_COLLECTION_UNLINK(mListenerManager)}NS_IMPL_CYCLE_COLLECTION_UNLINK(mTopInnerWindow)NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocation)NS_IMPL_CYCLE_COLLECTION_UNLINK(mHistory)NS_IMPL_CYCLE_COLLECTION_UNLINK(mCustomElements)NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocalStorage)NS_IMPL_CYCLE_COLLECTION_UNLINK(mSessionStorage)if(tmp->mApplicationCache){static_cast<nsDOMOfflineResourceList*>(tmp->mApplicationCache.get())->Disconnect();NS_IMPL_CYCLE_COLLECTION_UNLINK(mApplicationCache)}NS_IMPL_CYCLE_COLLECTION_UNLINK(mSuspendedDoc)NS_IMPL_CYCLE_COLLECTION_UNLINK(mIndexedDB)NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentPrincipal)NS_IMPL_CYCLE_COLLECTION_UNLINK(mTabChild)NS_IMPL_CYCLE_COLLECTION_UNLINK(mDoc)NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleService)NS_IMPL_CYCLE_COLLECTION_UNLINK(mWakeLock)NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleObservers)NS_IMPL_CYCLE_COLLECTION_UNLINK(mGamepads)NS_IMPL_CYCLE_COLLECTION_UNLINK(mCacheStorage)NS_IMPL_CYCLE_COLLECTION_UNLINK(mVRDisplays)// Unlink stuff from nsPIDOMWindowNS_IMPL_CYCLE_COLLECTION_UNLINK(mChromeEventHandler)NS_IMPL_CYCLE_COLLECTION_UNLINK(mParentTarget)NS_IMPL_CYCLE_COLLECTION_UNLINK(mFrameElement)NS_IMPL_CYCLE_COLLECTION_UNLINK(mFocusedNode)NS_IMPL_CYCLE_COLLECTION_UNLINK(mMenubar)NS_IMPL_CYCLE_COLLECTION_UNLINK(mToolbar)NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocationbar)NS_IMPL_CYCLE_COLLECTION_UNLINK(mPersonalbar)NS_IMPL_CYCLE_COLLECTION_UNLINK(mStatusbar)NS_IMPL_CYCLE_COLLECTION_UNLINK(mScrollbars)NS_IMPL_CYCLE_COLLECTION_UNLINK(mCrypto)NS_IMPL_CYCLE_COLLECTION_UNLINK(mU2F)NS_IMPL_CYCLE_COLLECTION_UNLINK(mConsole)NS_IMPL_CYCLE_COLLECTION_UNLINK(mAudioWorklet)NS_IMPL_CYCLE_COLLECTION_UNLINK(mPaintWorklet)NS_IMPL_CYCLE_COLLECTION_UNLINK(mExternal)NS_IMPL_CYCLE_COLLECTION_UNLINK(mMozSelfSupport)#ifdef ENABLE_INTL_APINS_IMPL_CYCLE_COLLECTION_UNLINK(mIntlUtils)#endiftmp->UnlinkHostObjectURIs();NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleRequestExecutor)tmp->DisableIdleCallbackRequests();NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPERNS_IMPL_CYCLE_COLLECTION_UNLINK_END#ifdef DEBUGvoidnsGlobalWindow::RiskyUnlink(){NS_CYCLE_COLLECTION_INNERNAME.Unlink(this);}#endifNS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsGlobalWindow)if(tmp->mCachedXBLPrototypeHandlers){for(autoiter=tmp->mCachedXBLPrototypeHandlers->Iter();!iter.Done();iter.Next()){aCallbacks.Trace(&iter.Data(),"Cached XBL prototype handler",aClosure);}}NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPERNS_IMPL_CYCLE_COLLECTION_TRACE_ENDboolnsGlobalWindow::IsBlackForCC(boolaTracingNeeded){if(!nsCCUncollectableMarker::sGeneration){returnfalse;}return(nsCCUncollectableMarker::InGeneration(GetMarkedCCGeneration())||HasKnownLiveWrapper())&&(!aTracingNeeded||HasNothingToTrace(static_cast<nsIDOMEventTarget*>(this)));}//*****************************************************************************// nsGlobalWindow::nsIScriptGlobalObject//*****************************************************************************nsresultnsGlobalWindow::EnsureScriptEnvironment(){nsGlobalWindow*outer=GetOuterWindowInternal();if(!outer){NS_WARNING("No outer window available!");returnNS_ERROR_FAILURE;}if(outer->GetWrapperPreserveColor()){returnNS_OK;}NS_ASSERTION(!outer->GetCurrentInnerWindowInternal(),"No cached wrapper, but we have an inner window?");// If this window is a [i]frame, don't bother GC'ing when the frame's context// is destroyed since a GC will happen when the frameset or host document is// destroyed anyway.nsCOMPtr<nsIScriptContext>context=newnsJSContext(!IsFrame(),outer);NS_ASSERTION(!outer->mContext,"Will overwrite mContext!");// should probably assert the context is clean???context->WillInitializeContext();nsresultrv=context->InitContext();NS_ENSURE_SUCCESS(rv,rv);outer->mContext=context;returnNS_OK;}nsIScriptContext*nsGlobalWindow::GetScriptContext(){nsGlobalWindow*outer=GetOuterWindowInternal();if(!outer){returnnullptr;}returnouter->mContext;}JSObject*nsGlobalWindow::GetGlobalJSObject(){returnFastGetGlobalJSObject();}voidnsGlobalWindow::TraceGlobalJSObject(JSTracer*aTrc){TraceWrapper(aTrc,"active window global");}boolnsGlobalWindow::WouldReuseInnerWindow(nsIDocument*aNewDocument){MOZ_ASSERT(IsOuterWindow());// We reuse the inner window when:// a. We are currently at our original document.// b. At least one of the following conditions are true:// -- The new document is the same as the old document. This means that we're// getting called from document.open().// -- The new document has the same origin as what we have loaded right now.if(!mDoc||!aNewDocument){returnfalse;}if(!mDoc->IsInitialDocument()){returnfalse;}#ifdef DEBUG{nsCOMPtr<nsIURI>uri;mDoc->GetDocumentURI()->CloneIgnoringRef(getter_AddRefs(uri));NS_ASSERTION(NS_IsAboutBlank(uri),"How'd this happen?");}#endif// Great, we're the original document, check for one of the other// conditions.if(mDoc==aNewDocument){returntrue;}boolequal;if(NS_SUCCEEDED(mDoc->NodePrincipal()->Equals(aNewDocument->NodePrincipal(),&equal))&&equal){// The origin is the same.returntrue;}returnfalse;}voidnsGlobalWindow::SetInitialPrincipalToSubject(){MOZ_ASSERT(IsOuterWindow());// First, grab the subject principal.nsCOMPtr<nsIPrincipal>newWindowPrincipal=nsContentUtils::SubjectPrincipalOrSystemIfNativeCaller();// We should never create windows with an expanded principal.// If we have a system principal, make sure we're not using it for a content// docshell.// NOTE: Please keep this logic in sync with nsWebShellWindow::Initialize().if(nsContentUtils::IsExpandedPrincipal(newWindowPrincipal)||(nsContentUtils::IsSystemPrincipal(newWindowPrincipal)&&GetDocShell()->ItemType()!=nsIDocShellTreeItem::typeChrome)){newWindowPrincipal=nullptr;}// If there's an existing document, bail if it either:if(mDoc){// (a) is not an initial about:blank document, orif(!mDoc->IsInitialDocument())return;// (b) already has the correct principal.if(mDoc->NodePrincipal()==newWindowPrincipal)return;#ifdef DEBUG// If we have a document loaded at this point, it had better be about:blank.// Otherwise, something is really weird. An about:blank page has a// NullPrincipal.boolisNullPrincipal;MOZ_ASSERT(NS_SUCCEEDED(mDoc->NodePrincipal()->GetIsNullPrincipal(&isNullPrincipal))&&isNullPrincipal);#endif}GetDocShell()->CreateAboutBlankContentViewer(newWindowPrincipal);mDoc->SetIsInitialDocument(true);nsCOMPtr<nsIPresShell>shell=GetDocShell()->GetPresShell();if(shell&&!shell->DidInitialize()){// Ensure that if someone plays with this document they will get// layout happening.nsRectr=shell->GetPresContext()->GetVisibleArea();shell->Initialize(r.width,r.height);}}PopupControlStatePushPopupControlState(PopupControlStateaState,boolaForce){MOZ_ASSERT(NS_IsMainThread());PopupControlStateoldState=gPopupControlState;if(aState<gPopupControlState||aForce){gPopupControlState=aState;}returnoldState;}voidPopPopupControlState(PopupControlStateaState){MOZ_ASSERT(NS_IsMainThread());gPopupControlState=aState;}PopupControlStatensGlobalWindow::PushPopupControlState(PopupControlStateaState,boolaForce)const{return::PushPopupControlState(aState,aForce);}voidnsGlobalWindow::PopPopupControlState(PopupControlStateaState)const{::PopPopupControlState(aState);}PopupControlStatensGlobalWindow::GetPopupControlState()const{MOZ_ASSERT(NS_IsMainThread());returngPopupControlState;}#define WINDOWSTATEHOLDER_IID \{0x0b917c3e, 0xbd50, 0x4683, {0xaf, 0xc9, 0xc7, 0x81, 0x07, 0xae, 0x33, 0x26}}classWindowStateHolderfinal:publicnsISupports{public:NS_DECLARE_STATIC_IID_ACCESSOR(WINDOWSTATEHOLDER_IID)NS_DECL_ISUPPORTSexplicitWindowStateHolder(nsGlobalWindow*aWindow);nsGlobalWindow*GetInnerWindow(){returnmInnerWindow;}voidDidRestoreWindow(){mInnerWindow=nullptr;mInnerWindowReflector=nullptr;}protected:~WindowStateHolder();nsGlobalWindow*mInnerWindow;// We hold onto this to make sure the inner window doesn't go away. The outer// window ends up recalculating it anyway.JS::PersistentRooted<JSObject*>mInnerWindowReflector;};NS_DEFINE_STATIC_IID_ACCESSOR(WindowStateHolder,WINDOWSTATEHOLDER_IID)WindowStateHolder::WindowStateHolder(nsGlobalWindow*aWindow):mInnerWindow(aWindow),mInnerWindowReflector(RootingCx(),aWindow->GetWrapper()){NS_PRECONDITION(aWindow,"null window");NS_PRECONDITION(aWindow->IsInnerWindow(),"Saving an outer window");aWindow->Suspend();// When a global goes into the bfcache, we disable script.xpc::Scriptability::Get(mInnerWindowReflector).SetDocShellAllowsScript(false);}WindowStateHolder::~WindowStateHolder(){if(mInnerWindow){// This window was left in the bfcache and is now going away. We need to// free it up.// Note that FreeInnerObjects may already have been called on the// inner window if its outer has already had SetDocShell(null)// called.mInnerWindow->FreeInnerObjects();}}NS_IMPL_ISUPPORTS(WindowStateHolder,WindowStateHolder)// We need certain special behavior for remote XUL whitelisted domains, but we// don't want that behavior to take effect in automation, because we whitelist// all the mochitest domains. So we need to check a pref here.staticboolTreatAsRemoteXUL(nsIPrincipal*aPrincipal){MOZ_ASSERT(!nsContentUtils::IsSystemPrincipal(aPrincipal));returnnsContentUtils::AllowXULXBLForPrincipal(aPrincipal)&&!Preferences::GetBool("dom.use_xbl_scopes_for_remote_xul",false);}staticboolEnablePrivilege(JSContext*cx,unsignedargc,JS::Value*vp){Telemetry::Accumulate(Telemetry::ENABLE_PRIVILEGE_EVER_CALLED,true);returnxpc::EnableUniversalXPConnect(cx);}staticconstJSFunctionSpecEnablePrivilegeSpec[]={JS_FS("enablePrivilege",EnablePrivilege,1,0),JS_FS_END};staticboolInitializeLegacyNetscapeObject(JSContext*aCx,JS::Handle<JSObject*>aGlobal){JSAutoCompartmentac(aCx,aGlobal);// Note: MathJax depends on window.netscape being exposed. See bug 791526.JS::Rooted<JSObject*>obj(aCx);obj=JS_DefineObject(aCx,aGlobal,"netscape",nullptr);NS_ENSURE_TRUE(obj,false);obj=JS_DefineObject(aCx,obj,"security",nullptr);NS_ENSURE_TRUE(obj,false);// We hide enablePrivilege behind a pref because it has been altered in a// way that makes it fundamentally insecure to use in production. Mozilla// uses this pref during automated testing to support legacy test code that// uses enablePrivilege. If you're not doing test automation, you _must_ not// flip this pref, or you will be exposing all your users to security// vulnerabilities.if(!xpc::IsInAutomation()){returntrue;}/* Define PrivilegeManager object with the necessary "static" methods. */obj=JS_DefineObject(aCx,obj,"PrivilegeManager",nullptr);NS_ENSURE_TRUE(obj,false);returnJS_DefineFunctions(aCx,obj,EnablePrivilegeSpec);}boolnsGlobalWindow::ComputeIsSecureContext(nsIDocument*aDocument,SecureContextFlagsaFlags){MOZ_ASSERT(IsOuterWindow());nsCOMPtr<nsIPrincipal>principal=aDocument->NodePrincipal();if(nsContentUtils::IsSystemPrincipal(principal)){returntrue;}// Implement https://w3c.github.io/webappsec-secure-contexts/#settings-object// With some modifications to allow for aFlags.boolhadNonSecureContextCreator=false;nsPIDOMWindowOuter*parentOuterWin=GetScriptableParent();MOZ_ASSERT(parentOuterWin,"How can we get here? No docShell somehow?");if(nsGlobalWindow::Cast(parentOuterWin)!=this){// There may be a small chance that parentOuterWin has navigated in// the time that it took us to start loading this sub-document. If that// were the case then parentOuterWin->GetCurrentInnerWindow() wouldn't// return the window for the document that is embedding us. For this// reason we only use the GetScriptableParent call above to check that we// have a same-type parent, but actually get the inner window via the// document that we know is embedding us.nsIDocument*creatorDoc=aDocument->GetParentDocument();if(!creatorDoc){returnfalse;// we must be tearing down}nsGlobalWindow*parentWin=nsGlobalWindow::Cast(creatorDoc->GetInnerWindow());if(!parentWin){returnfalse;// we must be tearing down}MOZ_ASSERT(parentWin==nsGlobalWindow::Cast(parentOuterWin->GetCurrentInnerWindow()),"Creator window mismatch while setting Secure Context state");if(aFlags!=SecureContextFlags::eIgnoreOpener){hadNonSecureContextCreator=!parentWin->IsSecureContext();}else{hadNonSecureContextCreator=!parentWin->IsSecureContextIfOpenerIgnored();}}elseif(mHadOriginalOpener){if(aFlags!=SecureContextFlags::eIgnoreOpener){hadNonSecureContextCreator=!mOriginalOpenerWasSecureContext;}}if(hadNonSecureContextCreator){returnfalse;}if(nsContentUtils::HttpsStateIsModern(aDocument)){returntrue;}if(principal->GetIsNullPrincipal()){nsCOMPtr<nsIURI>uri=aDocument->GetOriginalURI();// IsOriginPotentiallyTrustworthy doesn't care about origin attributes so// it doesn't actually matter what we use here, but reusing the document// principal's attributes is convenient.constOriginAttributes&attrs=principal->OriginAttributesRef();// CreateCodebasePrincipal correctly gets a useful principal for blob: and// other URI_INHERITS_SECURITY_CONTEXT URIs.principal=BasePrincipal::CreateCodebasePrincipal(uri,attrs);if(NS_WARN_IF(!principal)){returnfalse;}}nsCOMPtr<nsIContentSecurityManager>csm=do_GetService(NS_CONTENTSECURITYMANAGER_CONTRACTID);NS_WARNING_ASSERTION(csm,"csm is null");if(csm){boolisTrustworthyOrigin=false;csm->IsOriginPotentiallyTrustworthy(principal,&isTrustworthyOrigin);if(isTrustworthyOrigin){returntrue;}}returnfalse;}staticJS::CompartmentCreationOptions&SelectZoneGroup(nsGlobalWindow*aNewInner,JS::CompartmentCreationOptions&aOptions){JS::CompartmentCreationOptionsoptions;if(aNewInner->GetOuterWindow()){nsGlobalWindow*top=aNewInner->GetTopInternal();// If we have a top-level window, use its zone (and zone group).if(top&&top->GetGlobalJSObject()){returnaOptions.setExistingZone(top->GetGlobalJSObject());}}// If we're in the parent process, don't bother with zone groups.if(XRE_IsParentProcess()){returnaOptions.setNewZoneInSystemZoneGroup();}// Otherwise, find a zone group from the TabGroup. Typically we only have to// go through one iteration of this loop.RefPtr<TabGroup>tabGroup=aNewInner->TabGroup();for(nsPIDOMWindowOuter*outer:tabGroup->GetWindows()){nsGlobalWindow*window=nsGlobalWindow::Cast(outer);if(JSObject*global=window->GetGlobalJSObject()){returnaOptions.setNewZoneInExistingZoneGroup(global);}}returnaOptions.setNewZoneInNewZoneGroup();}/** * Create a new global object that will be used for an inner window. * Return the native global and an nsISupports 'holder' that can be used * to manage the lifetime of it. */staticnsresultCreateNativeGlobalForInner(JSContext*aCx,nsGlobalWindow*aNewInner,nsIURI*aURI,nsIPrincipal*aPrincipal,JS::MutableHandle<JSObject*>aGlobal,boolaIsSecureContext){MOZ_ASSERT(aCx);MOZ_ASSERT(aNewInner);MOZ_ASSERT(aNewInner->IsInnerWindow());MOZ_ASSERT(aPrincipal);// DOMWindow with nsEP is not supported, we have to make sure// no one creates one accidentally.nsCOMPtr<nsIExpandedPrincipal>nsEP=do_QueryInterface(aPrincipal);MOZ_RELEASE_ASSERT(!nsEP,"DOMWindow with nsEP is not supported");JS::CompartmentOptionsoptions;SelectZoneGroup(aNewInner,options.creationOptions());// Sometimes add-ons load their own XUL windows, either as separate top-level// windows or inside a browser element. In such cases we want to tag the// window's compartment with the add-on ID. See bug 1092156.if(nsContentUtils::IsSystemPrincipal(aPrincipal)){options.creationOptions().setAddonId(MapURIToAddonID(aURI));}options.creationOptions().setSecureContext(aIsSecureContext);xpc::InitGlobalObjectOptions(options,aPrincipal);// Determine if we need the Components object.boolneedComponents=nsContentUtils::IsSystemPrincipal(aPrincipal)||TreatAsRemoteXUL(aPrincipal);uint32_tflags=needComponents?0:nsIXPConnect::OMIT_COMPONENTS_OBJECT;flags|=nsIXPConnect::DONT_FIRE_ONNEWGLOBALHOOK;if(!WindowBinding::Wrap(aCx,aNewInner,aNewInner,options,nsJSPrincipals::get(aPrincipal),false,aGlobal)||!xpc::InitGlobalObject(aCx,aGlobal,flags)){returnNS_ERROR_FAILURE;}MOZ_ASSERT(aNewInner->GetWrapperPreserveColor()==aGlobal);// Set the location information for the new global, so that tools like// about:memory may use that informationxpc::SetLocationForGlobal(aGlobal,aURI);if(!InitializeLegacyNetscapeObject(aCx,aGlobal)){returnNS_ERROR_FAILURE;}returnNS_OK;}nsresultnsGlobalWindow::SetNewDocument(nsIDocument*aDocument,nsISupports*aState,boolaForceReuseInnerWindow){NS_PRECONDITION(mDocumentPrincipal==nullptr,"mDocumentPrincipal prematurely set!");MOZ_ASSERT(aDocument);if(IsInnerWindow()){if(!mOuterWindow){returnNS_ERROR_NOT_INITIALIZED;}// Refuse to set a new document if the call came from an inner// window that's not the current inner window.if(mOuterWindow->GetCurrentInnerWindow()!=AsInner()){returnNS_ERROR_NOT_AVAILABLE;}returnGetOuterWindowInternal()->SetNewDocument(aDocument,aState,aForceReuseInnerWindow);}NS_PRECONDITION(IsOuterWindow(),"Must only be called on outer windows");// Bail out early if we're in process of closing down the window.NS_ENSURE_STATE(!mCleanedUp);NS_ASSERTION(!AsOuter()->GetCurrentInnerWindow()||AsOuter()->GetCurrentInnerWindow()->GetExtantDoc()==mDoc,"Uh, mDoc doesn't match the current inner window ""document!");boolwouldReuseInnerWindow=WouldReuseInnerWindow(aDocument);if(aForceReuseInnerWindow&&!wouldReuseInnerWindow&&mDoc&&mDoc->NodePrincipal()!=aDocument->NodePrincipal()){NS_ERROR("Attempted forced inner window reuse while changing principal");returnNS_ERROR_UNEXPECTED;}nsCOMPtr<nsIDocument>oldDoc=mDoc;AutoJSAPIjsapi;jsapi.Init();JSContext*cx=jsapi.cx();// Check if we're anywhere near the stack limit before we reach the// transplanting code, since it has no good way to handle errors. This uses// the untrusted script limit, which is not strictly necessary since no// actual script should run.if(!js::CheckRecursionLimitConservativeDontReport(cx)){NS_WARNING("Overrecursion in SetNewDocument");returnNS_ERROR_FAILURE;}if(!mDoc){// First document load.// Get our private root. If it is equal to us, then we need to// attach our global key bindings that handles browser scrolling// and other browser commands.nsPIDOMWindowOuter*privateRoot=nsGlobalWindow::GetPrivateRoot();if(privateRoot==AsOuter()){nsXBLService::AttachGlobalKeyHandler(mChromeEventHandler);}}/* No mDocShell means we're already been partially closed down. When that happens, setting status isn't a big requirement, so don't. (Doesn't happen under normal circumstances, but bug 49615 describes a case.) */nsContentUtils::AddScriptRunner(NewRunnableMethod("nsGlobalWindow::ClearStatus",this,&nsGlobalWindow::ClearStatus));// Sometimes, WouldReuseInnerWindow() returns true even if there's no inner// window (see bug 776497). Be safe.boolreUseInnerWindow=(aForceReuseInnerWindow||wouldReuseInnerWindow)&&GetCurrentInnerWindowInternal();nsresultrv=NS_OK;// We set mDoc even though this is an outer window to avoid// having to *always* reach into the inner window to find the// document.mDoc=aDocument;// Take this opportunity to clear mSuspendedDoc. Our old inner window is now// responsible for unsuspending it.mSuspendedDoc=nullptr;#ifdef DEBUGmLastOpenedURI=aDocument->GetDocumentURI();#endifmContext->WillInitializeContext();nsGlobalWindow*currentInner=GetCurrentInnerWindowInternal();if(currentInner&¤tInner->mNavigator){currentInner->mNavigator->OnNavigation();}RefPtr<nsGlobalWindow>newInnerWindow;boolcreatedInnerWindow=false;boolthisChrome=IsChromeWindow();nsCOMPtr<WindowStateHolder>wsh=do_QueryInterface(aState);NS_ASSERTION(!aState||wsh,"What kind of weird state are you giving me here?");JS::Rooted<JSObject*>newInnerGlobal(cx);if(reUseInnerWindow){// We're reusing the current inner window.NS_ASSERTION(!currentInner->IsFrozen(),"We should never be reusing a shared inner window");newInnerWindow=currentInner;newInnerGlobal=currentInner->GetWrapperPreserveColor();if(aDocument!=oldDoc){JS::ExposeObjectToActiveJS(newInnerGlobal);}// We're reusing the inner window, but this still counts as a navigation,// so all expandos and such defined on the outer window should go away. Force// all Xray wrappers to be recomputed.JS::Rooted<JSObject*>rootedObject(cx,GetWrapper());if(!JS_RefreshCrossCompartmentWrappers(cx,rootedObject)){returnNS_ERROR_FAILURE;}// Inner windows are only reused for same-origin principals, but the principals// don't necessarily match exactly. Update the principal on the compartment to// match the new document.// NB: We don't just call currentInner->RefreshCompartmentPrincipals() here// because we haven't yet set its mDoc to aDocument.JSCompartment*compartment=js::GetObjectCompartment(newInnerGlobal);#ifdef DEBUGboolsameOrigin=false;nsIPrincipal*existing=nsJSPrincipals::get(JS_GetCompartmentPrincipals(compartment));aDocument->NodePrincipal()->Equals(existing,&sameOrigin);MOZ_ASSERT(sameOrigin);#endifMOZ_ASSERT_IF(aDocument==oldDoc,xpc::GetCompartmentPrincipal(compartment)==aDocument->NodePrincipal());if(aDocument!=oldDoc){JS_SetCompartmentPrincipals(compartment,nsJSPrincipals::get(aDocument->NodePrincipal()));// Make sure we clear out the old content XBL scope, so the new one will// get created with a principal that subsumes our new principal.xpc::ClearContentXBLScope(newInnerGlobal);}}else{if(aState){newInnerWindow=wsh->GetInnerWindow();newInnerGlobal=newInnerWindow->GetWrapperPreserveColor();}else{if(thisChrome){newInnerWindow=nsGlobalChromeWindow::Create(this);}elseif(mIsModalContentWindow){newInnerWindow=nsGlobalModalWindow::Create(this);}else{newInnerWindow=nsGlobalWindow::Create(this);}// The outer window is automatically treated as frozen when we// null out the inner window. As a result, initializing classes// on the new inner won't end up reaching into the old inner// window for classes etc.//// [This happens with Object.prototype when XPConnect creates// a temporary global while initializing classes; the reason// being that xpconnect creates the temp global w/o a parent// and proto, which makes the JS engine look up classes in// cx->globalObject, i.e. this outer window].mInnerWindow=nullptr;mCreatingInnerWindow=true;// Every script context we are initialized with must create a// new global.rv=CreateNativeGlobalForInner(cx,newInnerWindow,aDocument->GetDocumentURI(),aDocument->NodePrincipal(),&newInnerGlobal,ComputeIsSecureContext(aDocument));NS_ASSERTION(NS_SUCCEEDED(rv)&&newInnerGlobal&&newInnerWindow->GetWrapperPreserveColor()==newInnerGlobal,"Failed to get script global");newInnerWindow->mIsSecureContextIfOpenerIgnored=ComputeIsSecureContext(aDocument,SecureContextFlags::eIgnoreOpener);mCreatingInnerWindow=false;createdInnerWindow=true;NS_ENSURE_SUCCESS(rv,rv);}if(currentInner&¤tInner->GetWrapperPreserveColor()){if(oldDoc==aDocument){// Make a copy of the old window's performance object on document.open.// Note that we have to force eager creation of it here, because we need// to grab the current document channel and whatnot before that changes.currentInner->AsInner()->CreatePerformanceObjectIfNeeded();if(currentInner->mPerformance){newInnerWindow->mPerformance=Performance::CreateForMainThread(newInnerWindow->AsInner(),currentInner->mPerformance->GetDOMTiming(),currentInner->mPerformance->GetChannel());}}// Don't free objects on our current inner window if it's going to be// held in the bfcache.if(!currentInner->IsFrozen()){currentInner->FreeInnerObjects();}}mInnerWindow=newInnerWindow->AsInner();MOZ_ASSERT(mInnerWindow);mInnerWindow->TryToCacheTopInnerWindow();if(!GetWrapperPreserveColor()){JS::Rooted<JSObject*>outer(cx,NewOuterWindowProxy(cx,newInnerGlobal,thisChrome));NS_ENSURE_TRUE(outer,NS_ERROR_FAILURE);js::SetProxyReservedSlot(outer,0,js::PrivateValue(ToSupports(this)));// Inform the nsJSContext, which is the canonical holder of the outer.mContext->SetWindowProxy(outer);mContext->DidInitializeContext();SetWrapper(mContext->GetWindowProxy());}else{JS::ExposeObjectToActiveJS(newInnerGlobal);JS::Rooted<JSObject*>outerObject(cx,NewOuterWindowProxy(cx,newInnerGlobal,thisChrome));if(!outerObject){NS_ERROR("out of memory");returnNS_ERROR_FAILURE;}JS::Rooted<JSObject*>obj(cx,GetWrapperPreserveColor());js::SetProxyReservedSlot(obj,0,js::PrivateValue(nullptr));js::SetProxyReservedSlot(outerObject,0,js::PrivateValue(nullptr));outerObject=xpc::TransplantObject(cx,obj,outerObject);if(!outerObject){NS_ERROR("unable to transplant wrappers, probably OOM");returnNS_ERROR_FAILURE;}js::SetProxyReservedSlot(outerObject,0,js::PrivateValue(ToSupports(this)));SetWrapper(outerObject);MOZ_ASSERT(js::GetGlobalForObjectCrossCompartment(outerObject)==newInnerGlobal);// Inform the nsJSContext, which is the canonical holder of the outer.mContext->SetWindowProxy(outerObject);}// Enter the new global's compartment.JSAutoCompartmentac(cx,GetWrapperPreserveColor());{JS::Rooted<JSObject*>outer(cx,GetWrapperPreserveColor());js::SetWindowProxy(cx,newInnerGlobal,outer);}// Set scriptability based on the state of the docshell.boolallow=GetDocShell()->GetCanExecuteScripts();xpc::Scriptability::Get(GetWrapperPreserveColor()).SetDocShellAllowsScript(allow);if(!aState){// Get the "window" property once so it will be cached on our inner. We// have to do this here, not in binding code, because this has to happen// after we've created the outer window proxy and stashed it in the outer// nsGlobalWindow, so GetWrapperPreserveColor() on that outer// nsGlobalWindow doesn't return null and nsGlobalWindow::OuterObject// works correctly.JS::Rooted<JS::Value>unused(cx);if(!JS_GetProperty(cx,newInnerGlobal,"window",&unused)){NS_ERROR("can't create the 'window' property");returnNS_ERROR_FAILURE;}// And same thing for the "self" property.if(!JS_GetProperty(cx,newInnerGlobal,"self",&unused)){NS_ERROR("can't create the 'self' property");returnNS_ERROR_FAILURE;}}}JSAutoCompartmentac(cx,GetWrapperPreserveColor());if(!aState&&!reUseInnerWindow){// Loading a new page and creating a new inner window, *not*// restoring from session history.// Now that both the the inner and outer windows are initialized// let the script context do its magic to hook them together.MOZ_ASSERT(mContext->GetWindowProxy()==GetWrapperPreserveColor());#ifdef DEBUGJS::Rooted<JSObject*>rootedJSObject(cx,GetWrapperPreserveColor());JS::Rooted<JSObject*>proto1(cx),proto2(cx);JS_GetPrototype(cx,rootedJSObject,&proto1);JS_GetPrototype(cx,newInnerGlobal,&proto2);NS_ASSERTION(proto1==proto2,"outer and inner globals should have the same prototype");#endifmInnerWindow->SyncStateFromParentWindow();}// Add an extra ref in case we release mContext during GC.nsCOMPtr<nsIScriptContext>kungFuDeathGrip(mContext);aDocument->SetScriptGlobalObject(newInnerWindow);MOZ_ASSERT(newInnerWindow->mTabGroup,"We must have a TabGroup cached at this point");if(!aState){if(reUseInnerWindow){if(newInnerWindow->mDoc!=aDocument){newInnerWindow->mDoc=aDocument;// The storage objects contain the URL of the window. We have to// recreate them when the innerWindow is reused.newInnerWindow->mLocalStorage=nullptr;newInnerWindow->mSessionStorage=nullptr;newInnerWindow->ClearDocumentDependentSlots(cx);}}else{newInnerWindow->InnerSetNewDocument(cx,aDocument);// Initialize DOM classes etc on the inner window.JS::Rooted<JSObject*>obj(cx,newInnerGlobal);rv=kungFuDeathGrip->InitClasses(obj);NS_ENSURE_SUCCESS(rv,rv);}// If the document comes from a JAR, check if the channel was determined// to be unsafe. If so, permanently disable script on the compartment by// calling Block() and throwing away the key.nsCOMPtr<nsIJARChannel>jarChannel=do_QueryInterface(aDocument->GetChannel());if(jarChannel&&jarChannel->GetIsUnsafe()){xpc::Scriptability::Get(newInnerGlobal).Block();}if(mArguments){newInnerWindow->DefineArgumentsProperty(mArguments);mArguments=nullptr;}// Give the new inner window our chrome event handler (since it// doesn't have one).newInnerWindow->mChromeEventHandler=mChromeEventHandler;}// Ask the JS engine to assert that it's valid to access our DocGroup whenever// it runs JS code for this compartment. We skip the check if this window is// for chrome JS or an add-on.nsCOMPtr<nsIPrincipal>principal=mDoc->NodePrincipal();nsStringaddonId;principal->GetAddonId(addonId);if(GetDocGroup()&&!nsContentUtils::IsSystemPrincipal(principal)&&addonId.IsEmpty()){js::SetCompartmentValidAccessPtr(cx,newInnerGlobal,newInnerWindow->GetDocGroup()->GetValidAccessPtr());}kungFuDeathGrip->DidInitializeContext();// We wait to fire the debugger hook until the window is all set up and hooked// up with the outer. See bug 969156.if(createdInnerWindow){nsContentUtils::AddScriptRunner(NewRunnableMethod("nsGlobalWindow::FireOnNewGlobalObject",newInnerWindow,&nsGlobalWindow::FireOnNewGlobalObject));}if(newInnerWindow&&!newInnerWindow->mHasNotifiedGlobalCreated&&mDoc){// We should probably notify. However if this is the, arguably bad,// situation when we're creating a temporary non-chrome-about-blank// document in a chrome docshell, don't notify just yet. Instead wait// until we have a real chrome doc.if(!mDocShell||mDocShell->ItemType()!=nsIDocShellTreeItem::typeChrome||nsContentUtils::IsSystemPrincipal(mDoc->NodePrincipal())){newInnerWindow->mHasNotifiedGlobalCreated=true;nsContentUtils::AddScriptRunner(NewRunnableMethod("nsGlobalWindow::DispatchDOMWindowCreated",this,&nsGlobalWindow::DispatchDOMWindowCreated));}}PreloadLocalStorage();// If we have a recorded interesting Large-Allocation header status, report it// to the newly attached document.ReportLargeAllocStatus();mLargeAllocStatus=LargeAllocStatus::NONE;returnNS_OK;}voidnsGlobalWindow::PreloadLocalStorage(){MOZ_ASSERT(IsOuterWindow());if(!Preferences::GetBool(kStorageEnabled)){return;}if(IsChromeWindow()){return;}nsIPrincipal*principal=GetPrincipal();if(!principal){return;}nsresultrv;nsCOMPtr<nsIDOMStorageManager>storageManager=do_GetService("@mozilla.org/dom/localStorage-manager;1",&rv);if(NS_FAILED(rv)){return;}// private browsing windows do not persist local storage to disk so we should// only try to precache storage when we're not a private browsing window.if(principal->GetPrivateBrowsingId()==0){nsCOMPtr<nsIDOMStorage>storage;rv=storageManager->PrecacheStorage(principal,getter_AddRefs(storage));if(NS_SUCCEEDED(rv)){mLocalStorage=static_cast<Storage*>(storage.get());}}}voidnsGlobalWindow::DispatchDOMWindowCreated(){MOZ_ASSERT(IsOuterWindow());if(!mDoc){return;}// Fire DOMWindowCreated at chrome event listenersnsContentUtils::DispatchChromeEvent(mDoc,mDoc,NS_LITERAL_STRING("DOMWindowCreated"),true/* bubbles */,false/* not cancellable */);nsCOMPtr<nsIObserverService>observerService=mozilla::services::GetObserverService();// The event dispatching could possibly cause docshell destory, and// consequently cause mDoc to be set to nullptr by DropOuterWindowDocs(),// so check it again here.if(observerService&&mDoc){nsAutoStringorigin;nsIPrincipal*principal=mDoc->NodePrincipal();nsContentUtils::GetUTFOrigin(principal,origin);observerService->NotifyObservers(static_cast<nsIDOMWindow*>(this),nsContentUtils::IsSystemPrincipal(principal)?"chrome-document-global-created":"content-document-global-created",origin.get());}}voidnsGlobalWindow::ClearStatus(){SetStatusOuter(EmptyString());}voidnsGlobalWindow::InnerSetNewDocument(JSContext*aCx,nsIDocument*aDocument){NS_PRECONDITION(IsInnerWindow(),"Must only be called on inner windows");MOZ_ASSERT(aDocument);if(MOZ_LOG_TEST(gDOMLeakPRLog,LogLevel::Debug)){nsIURI*uri=aDocument->GetDocumentURI();MOZ_LOG(gDOMLeakPRLog,LogLevel::Debug,("DOMWINDOW %p SetNewDocument %s",this,uri?uri->GetSpecOrDefault().get():""));}mDoc=aDocument;ClearDocumentDependentSlots(aCx);mFocusedNode=nullptr;mLocalStorage=nullptr;mSessionStorage=nullptr;#ifdef DEBUGmLastOpenedURI=aDocument->GetDocumentURI();#endifTelemetry::Accumulate(Telemetry::INNERWINDOWS_WITH_MUTATION_LISTENERS,mMutationBits?1:0);// Clear our mutation bitfield.mMutationBits=0;}voidnsGlobalWindow::SetDocShell(nsIDocShell*aDocShell){NS_ASSERTION(IsOuterWindow(),"Uh, SetDocShell() called on inner window!");MOZ_ASSERT(aDocShell);if(aDocShell==mDocShell){return;}mDocShell=aDocShell;// Weak ReferencensCOMPtr<nsPIDOMWindowOuter>parentWindow=GetScriptableParentOrNull();MOZ_RELEASE_ASSERT(!parentWindow||!mTabGroup||mTabGroup==Cast(parentWindow)->mTabGroup);mTopLevelOuterContentWindow=!mIsChrome&&GetScriptableTopInternal()==this;NS_ASSERTION(!mNavigator,"Non-null mNavigator in outer window!");if(mFrames){mFrames->SetDocShell(aDocShell);}// Get our enclosing chrome shell and retrieve its global window impl, so// that we can do some forwarding to the chrome document.nsCOMPtr<nsIDOMEventTarget>chromeEventHandler;mDocShell->GetChromeEventHandler(getter_AddRefs(chromeEventHandler));mChromeEventHandler=do_QueryInterface(chromeEventHandler);if(!mChromeEventHandler){// We have no chrome event handler. If we have a parent,// get our chrome event handler from the parent. If// we don't have a parent, then we need to make a new// window root object that will function as a chrome event// handler and receive all events that occur anywhere inside// our window.nsCOMPtr<nsPIDOMWindowOuter>parentWindow=GetParent();if(parentWindow.get()!=AsOuter()){mChromeEventHandler=parentWindow->GetChromeEventHandler();}else{mChromeEventHandler=NS_NewWindowRoot(AsOuter());mIsRootOuterWindow=true;}}booldocShellActive;mDocShell->GetIsActive(&docShellActive);SetIsBackgroundInternal(!docShellActive);}voidnsGlobalWindow::DetachFromDocShell(){NS_ASSERTION(IsOuterWindow(),"Uh, DetachFromDocShell() called on inner window!");// DetachFromDocShell means the window is being torn down. Drop our// reference to the script context, allowing it to be deleted// later. Meanwhile, keep our weak reference to the script object// so that it can be retrieved later (until it is finalized by the JS GC).// Call FreeInnerObjects on all inner windows, not just the current// one, since some could be held by WindowStateHolder objects that// are GC-owned.for(RefPtr<nsGlobalWindow>inner=(nsGlobalWindow*)PR_LIST_HEAD(this);inner!=this;inner=(nsGlobalWindow*)PR_NEXT_LINK(inner)){MOZ_ASSERT(!inner->mOuterWindow||inner->mOuterWindow==AsOuter());inner->FreeInnerObjects();}if(auto*reporter=nsWindowMemoryReporter::Get()){reporter->ObserveDOMWindowDetached(this);}NotifyWindowIDDestroyed("outer-window-destroyed");nsGlobalWindow*currentInner=GetCurrentInnerWindowInternal();if(currentInner){NS_ASSERTION(mDoc,"Must have doc!");// Remember the document's principal and URI.mDocumentPrincipal=mDoc->NodePrincipal();mDocumentURI=mDoc->GetDocumentURI();mDocBaseURI=mDoc->GetDocBaseURI();// Release our document referenceDropOuterWindowDocs();mFocusedNode=nullptr;}ClearControllers();mChromeEventHandler=nullptr;// force release nowif(mContext){// When we're about to destroy a top level content window// (for example a tab), we trigger a full GC by passing null as the last// param. We also trigger a full GC for chrome windows.nsJSContext::PokeGC(JS::gcreason::SET_DOC_SHELL,(mTopLevelOuterContentWindow||mIsChrome)?nullptr:GetWrapperPreserveColor());mContext=nullptr;}mDocShell=nullptr;// Weak ReferenceNS_ASSERTION(!mNavigator,"Non-null mNavigator in outer window!");if(mFrames){mFrames->SetDocShell(nullptr);}MaybeForgiveSpamCount();CleanUp();}voidnsGlobalWindow::SetOpenerWindow(nsPIDOMWindowOuter*aOpener,boolaOriginalOpener){FORWARD_TO_OUTER_VOID(SetOpenerWindow,(aOpener,aOriginalOpener));nsWeakPtropener=do_GetWeakReference(aOpener);if(opener==mOpener){return;}NS_ASSERTION(!aOriginalOpener||!mSetOpenerWindowCalled,"aOriginalOpener is true, but not first call to ""SetOpenerWindow!");NS_ASSERTION(aOpener||!aOriginalOpener,"Shouldn't set mHadOriginalOpener if aOpener is null");mOpener=opener.forget();NS_ASSERTION(mOpener||!aOpener,"Opener must support weak references!");// Check that the js visible opener matches! We currently don't depend on this// being true outside of nightly, so we disable the assertion in optimized// release / beta builds.nsPIDOMWindowOuter*contentOpener=GetSanitizedOpener(aOpener);// contentOpener is not used when the DIAGNOSTIC_ASSERT is compiled out.mozilla::Unused<<contentOpener;MOZ_DIAGNOSTIC_ASSERT(!contentOpener||!mTabGroup||mTabGroup==Cast(contentOpener)->mTabGroup);if(aOriginalOpener){MOZ_ASSERT(!mHadOriginalOpener,"Probably too late to call ComputeIsSecureContext again");mHadOriginalOpener=true;mOriginalOpenerWasSecureContext=aOpener->GetCurrentInnerWindow()->IsSecureContext();}#ifdef DEBUGmSetOpenerWindowCalled=true;#endif}staticalready_AddRefed<EventTarget>TryGetTabChildGlobalAsEventTarget(nsISupports*aFrom){nsCOMPtr<nsIFrameLoaderOwner>frameLoaderOwner=do_QueryInterface(aFrom);if(!frameLoaderOwner){returnnullptr;}RefPtr<nsFrameLoader>frameLoader=frameLoaderOwner->GetFrameLoader();if(!frameLoader){returnnullptr;}nsCOMPtr<EventTarget>target=frameLoader->GetTabChildGlobalAsEventTarget();returntarget.forget();}voidnsGlobalWindow::UpdateParentTarget(){// Try to get our frame element's tab child global (its in-process message// manager). If that fails, fall back to the chrome event handler's tab// child global, and if it doesn't have one, just use the chrome event// handler itself.nsCOMPtr<Element>frameElement=GetOuterWindow()->GetFrameElementInternal();nsCOMPtr<EventTarget>eventTarget=TryGetTabChildGlobalAsEventTarget(frameElement);if(!eventTarget){nsGlobalWindow*topWin=GetScriptableTopInternal();if(topWin){frameElement=topWin->AsOuter()->GetFrameElementInternal();eventTarget=TryGetTabChildGlobalAsEventTarget(frameElement);}}if(!eventTarget){eventTarget=TryGetTabChildGlobalAsEventTarget(mChromeEventHandler);}if(!eventTarget){eventTarget=mChromeEventHandler;}mParentTarget=eventTarget;}EventTarget*nsGlobalWindow::GetTargetForDOMEvent(){returnGetOuterWindowInternal();}EventTarget*nsGlobalWindow::GetTargetForEventTargetChain(){returnIsInnerWindow()?this:GetCurrentInnerWindowInternal();}nsresultnsGlobalWindow::WillHandleEvent(EventChainPostVisitor&aVisitor){returnNS_OK;}nsresultnsGlobalWindow::GetEventTargetParent(EventChainPreVisitor&aVisitor){NS_PRECONDITION(IsInnerWindow(),"GetEventTargetParent is used on outer window!?");EventMessagemsg=aVisitor.mEvent->mMessage;aVisitor.mCanHandle=true;aVisitor.mForceContentDispatch=true;//FIXME! Bug 329119if(msg==eResize&&aVisitor.mEvent->IsTrusted()){// QIing to window so that we can keep the old behavior also in case// a child window is handling resize.nsCOMPtr<nsPIDOMWindowInner>window=do_QueryInterface(aVisitor.mEvent->mOriginalTarget);if(window){mIsHandlingResizeEvent=true;}}elseif(msg==eMouseDown&&aVisitor.mEvent->IsTrusted()){gMouseDown=true;}elseif((msg==eMouseUp||msg==eDragEnd)&&aVisitor.mEvent->IsTrusted()){gMouseDown=false;if(gDragServiceDisabled){nsCOMPtr<nsIDragService>ds=do_GetService("@mozilla.org/widget/dragservice;1");if(ds){gDragServiceDisabled=false;ds->Unsuppress();}}}aVisitor.mParentTarget=GetParentTarget();// Handle 'active' event.if(!mIdleObservers.IsEmpty()&&aVisitor.mEvent->IsTrusted()&&(aVisitor.mEvent->HasMouseEventMessage()||aVisitor.mEvent->HasDragEventMessage())){mAddActiveEventFuzzTime=false;}returnNS_OK;}boolnsGlobalWindow::ShouldPromptToBlockDialogs(){MOZ_ASSERT(IsOuterWindow());nsGlobalWindow*topWindow=GetScriptableTopInternal();if(!topWindow){NS_ASSERTION(!mDocShell,"ShouldPromptToBlockDialogs() called without a top window?");returntrue;}topWindow=topWindow->GetCurrentInnerWindowInternal();if(!topWindow){returntrue;}returntopWindow->DialogsAreBeingAbused();}boolnsGlobalWindow::AreDialogsEnabled(){MOZ_ASSERT(IsOuterWindow());nsGlobalWindow*topWindow=GetScriptableTopInternal();if(!topWindow){NS_ERROR("AreDialogsEnabled() called without a top window?");returnfalse;}// TODO: Warn if no top window?topWindow=topWindow->GetCurrentInnerWindowInternal();if(!topWindow){returnfalse;}// Dialogs are blocked if the content viewer is hiddenif(mDocShell){nsCOMPtr<nsIContentViewer>cv;mDocShell->GetContentViewer(getter_AddRefs(cv));boolisHidden;cv->GetIsHidden(&isHidden);if(isHidden){returnfalse;}}// Dialogs are also blocked if the document is sandboxed with SANDBOXED_MODALS// (or if we have no document, of course). Which document? Who knows; the// spec is daft. See <https://github.com/whatwg/html/issues/1206>. For now// just go ahead and check mDoc, since in everything except edge cases in// which a frame is allow-same-origin but not allow-scripts and is being poked// at by some other window this should be the right thing anyway.if(!mDoc||(mDoc->GetSandboxFlags()&SANDBOXED_MODALS)){returnfalse;}returntopWindow->mAreDialogsEnabled;}boolnsGlobalWindow::DialogsAreBeingAbused(){MOZ_ASSERT(IsInnerWindow());NS_ASSERTION(GetScriptableTopInternal()&&GetScriptableTopInternal()->GetCurrentInnerWindowInternal()==this,"DialogsAreBeingAbused called with invalid window");if(mLastDialogQuitTime.IsNull()||nsContentUtils::IsCallerChrome()){returnfalse;}TimeDurationdialogInterval(TimeStamp::Now()-mLastDialogQuitTime);if(dialogInterval.ToSeconds()<Preferences::GetInt("dom.successive_dialog_time_limit",DEFAULT_SUCCESSIVE_DIALOG_TIME_LIMIT)){mDialogAbuseCount++;returnGetPopupControlState()>openAllowed||mDialogAbuseCount>MAX_SUCCESSIVE_DIALOG_COUNT;}// Reset the abuse countermDialogAbuseCount=0;returnfalse;}boolnsGlobalWindow::ConfirmDialogIfNeeded(){MOZ_ASSERT(IsOuterWindow());NS_ENSURE_TRUE(mDocShell,false);nsCOMPtr<nsIPromptService>promptSvc=do_GetService("@mozilla.org/embedcomp/prompt-service;1");if(!promptSvc){returntrue;}// Reset popup state while opening a modal dialog, and firing events// about the dialog, to prevent the current state from being active// the whole time a modal dialog is open.nsAutoPopupStatePusherpopupStatePusher(openAbused,true);booldisableDialog=false;nsXPIDLStringlabel,title;nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,"ScriptDialogLabel",label);nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,"ScriptDialogPreventTitle",title);promptSvc->Confirm(AsOuter(),title.get(),label.get(),&disableDialog);if(disableDialog){DisableDialogs();returnfalse;}returntrue;}voidnsGlobalWindow::DisableDialogs(){nsGlobalWindow*topWindow=GetScriptableTopInternal();if(!topWindow){NS_ERROR("DisableDialogs() called without a top window?");return;}topWindow=topWindow->GetCurrentInnerWindowInternal();// TODO: Warn if no top window?if(topWindow){topWindow->mAreDialogsEnabled=false;}}voidnsGlobalWindow::EnableDialogs(){nsGlobalWindow*topWindow=GetScriptableTopInternal();if(!topWindow){NS_ERROR("EnableDialogs() called without a top window?");return;}// TODO: Warn if no top window?topWindow=topWindow->GetCurrentInnerWindowInternal();if(topWindow){topWindow->mAreDialogsEnabled=true;}}nsresultnsGlobalWindow::PostHandleEvent(EventChainPostVisitor&aVisitor){NS_PRECONDITION(IsInnerWindow(),"PostHandleEvent is used on outer window!?");// Return early if there is nothing to do.switch(aVisitor.mEvent->mMessage){caseeResize:caseeUnload:caseeLoad:break;default:returnNS_OK;}/* mChromeEventHandler and mContext go dangling in the middle of this function under some circumstances (events that destroy the window) without this addref. */nsCOMPtr<nsIDOMEventTarget>kungFuDeathGrip1(mChromeEventHandler);mozilla::Unused<<kungFuDeathGrip1;// These aren't referred to through the functionnsCOMPtr<nsIScriptContext>kungFuDeathGrip2(GetContextInternal());mozilla::Unused<<kungFuDeathGrip2;// These aren't referred to through the functionif(aVisitor.mEvent->mMessage==eResize){mIsHandlingResizeEvent=false;}elseif(aVisitor.mEvent->mMessage==eUnload&&aVisitor.mEvent->IsTrusted()){// If any VR display presentation is active at unload, the next page// will receive a vrdisplayactive event to indicate that it should// immediately begin vr presentation. This should occur when navigating// forwards, navigating backwards, and on page reload.for(constauto&display:mVRDisplays){if(display->IsPresenting()){// Save this VR display ID to trigger vrdisplayactivate event// after the next load event.nsGlobalWindow*outer=GetOuterWindowInternal();if(outer){outer->SetAutoActivateVRDisplayID(display->DisplayId());}// XXX The WebVR 1.1 spec does not define which of multiple VR// presenting VR displays will be chosen during navigation.// As the underlying platform VR API's currently only allow a single// VR display, it is safe to choose the first VR display for now.break;}}// Execute bindingdetached handlers before we tear ourselves// down.if(mDoc){mDoc->BindingManager()->ExecuteDetachedHandlers();}mIsDocumentLoaded=false;}elseif(aVisitor.mEvent->mMessage==eLoad&&aVisitor.mEvent->IsTrusted()){// This is page load event since load events don't propagate to |window|.// @see nsDocument::GetEventTargetParent.mIsDocumentLoaded=true;mTimeoutManager->OnDocumentLoaded();nsCOMPtr<Element>element=GetOuterWindow()->GetFrameElementInternal();nsIDocShell*docShell=GetDocShell();if(element&&GetParentInternal()&&docShell&&docShell->ItemType()!=nsIDocShellTreeItem::typeChrome){// If we're not in chrome, or at a chrome boundary, fire the// onload event for the frame element.nsEventStatusstatus=nsEventStatus_eIgnore;WidgetEventevent(aVisitor.mEvent->IsTrusted(),eLoad);event.mFlags.mBubbles=false;event.mFlags.mCancelable=false;// Most of the time we could get a pres context to pass in here,// but not always (i.e. if this window is not shown there won't// be a pres context available). Since we're not firing a GUI// event we don't need a pres context anyway so we just pass// null as the pres context all the time here.EventDispatcher::Dispatch(element,nullptr,&event,nullptr,&status);}uint32_tautoActivateVRDisplayID=0;nsGlobalWindow*outer=GetOuterWindowInternal();if(outer){autoActivateVRDisplayID=outer->GetAutoActivateVRDisplayID();}if(autoActivateVRDisplayID){DispatchVRDisplayActivate(autoActivateVRDisplayID,VRDisplayEventReason::Navigation);}}returnNS_OK;}nsresultnsGlobalWindow::DispatchDOMEvent(WidgetEvent*aEvent,nsIDOMEvent*aDOMEvent,nsPresContext*aPresContext,nsEventStatus*aEventStatus){returnEventDispatcher::DispatchDOMEvent(static_cast<nsPIDOMWindow*>(this),aEvent,aDOMEvent,aPresContext,aEventStatus);}voidnsGlobalWindow::PoisonOuterWindowProxy(JSObject*aObject){MOZ_ASSERT(IsOuterWindow());if(aObject==GetWrapperMaybeDead()){PoisonWrapper();}}nsresultnsGlobalWindow::SetArguments(nsIArray*aArguments){MOZ_ASSERT(IsOuterWindow());nsresultrv;// Historically, we've used the same machinery to handle openDialog arguments// (exposed via window.arguments) and showModalDialog arguments (exposed via// window.dialogArguments), even though the former is XUL-only and uses an XPCOM// array while the latter is web-exposed and uses an arbitrary JS value.// Moreover, per-spec |dialogArguments| is a property of the browsing context// (outer), whereas |arguments| lives on the inner.//// We've now mostly separated them, but the difference is still opaque to// nsWindowWatcher (the caller of SetArguments in this little back-and-forth// embedding waltz we do here).//// So we need to demultiplex the two cases here.nsGlobalWindow*currentInner=GetCurrentInnerWindowInternal();if(mIsModalContentWindow){// nsWindowWatcher blindly converts the original nsISupports into an array// of length 1. We need to recover it, and then cast it back to the concrete// object we know it to be.nsCOMPtr<nsISupports>supports=do_QueryElementAt(aArguments,0,&rv);NS_ENSURE_SUCCESS(rv,rv);mDialogArguments=static_cast<DialogValueHolder*>(supports.get());}else{mArguments=aArguments;rv=currentInner->DefineArgumentsProperty(aArguments);NS_ENSURE_SUCCESS(rv,rv);}returnNS_OK;}nsresultnsGlobalWindow::DefineArgumentsProperty(nsIArray*aArguments){MOZ_ASSERT(IsInnerWindow());MOZ_ASSERT(!mIsModalContentWindow);// Handled separately.nsIScriptContext*ctx=GetOuterWindowInternal()->mContext;NS_ENSURE_TRUE(aArguments&&ctx,NS_ERROR_NOT_INITIALIZED);JS::Rooted<JSObject*>obj(RootingCx(),GetWrapperPreserveColor());returnctx->SetProperty(obj,"arguments",aArguments);}//*****************************************************************************// nsGlobalWindow::nsIScriptObjectPrincipal//*****************************************************************************nsIPrincipal*nsGlobalWindow::GetPrincipal(){if(mDoc){// If we have a document, get the principal from the documentreturnmDoc->NodePrincipal();}if(mDocumentPrincipal){returnmDocumentPrincipal;}// If we don't have a principal and we don't have a document we// ask the parent window for the principal. This can happen when// loading a frameset that has a <frame src="javascript:xxx">, in// that case the global window is used in JS before we've loaded// a document into the window.nsCOMPtr<nsIScriptObjectPrincipal>objPrincipal=do_QueryInterface(GetParentInternal());if(objPrincipal){returnobjPrincipal->GetPrincipal();}returnnullptr;}//*****************************************************************************// nsGlobalWindow::nsIDOMWindow//*****************************************************************************template<classT>nsIURI*nsPIDOMWindow<T>::GetDocumentURI()const{returnmDoc?mDoc->GetDocumentURI():mDocumentURI.get();}template<classT>nsIURI*nsPIDOMWindow<T>::GetDocBaseURI()const{returnmDoc?mDoc->GetDocBaseURI():mDocBaseURI.get();}template<classT>voidnsPIDOMWindow<T>::MaybeCreateDoc(){MOZ_ASSERT(!mDoc);if(nsIDocShell*docShell=GetDocShell()){// Note that |document| here is the same thing as our mDoc, but we// don't have to explicitly set the member variable because the docshell// has already called SetNewDocument().nsCOMPtr<nsIDocument>document=docShell->GetDocument();Unused<<document;}}voidnsPIDOMWindowOuter::SetInitialKeyboardIndicators(UIStateChangeTypeaShowAccelerators,UIStateChangeTypeaShowFocusRings){MOZ_ASSERT(IsOuterWindow());MOZ_ASSERT(!GetCurrentInnerWindow());nsPIDOMWindowOuter*piWin=GetPrivateRoot();if(!piWin){return;}MOZ_ASSERT(piWin==AsOuter());// only change the flags that have been modifiednsCOMPtr<nsPIWindowRoot>windowRoot=do_QueryInterface(mChromeEventHandler);if(!windowRoot){return;}if(aShowAccelerators!=UIStateChangeType_NoChange){windowRoot->SetShowAccelerators(aShowAccelerators==UIStateChangeType_Set);}if(aShowFocusRings!=UIStateChangeType_NoChange){windowRoot->SetShowFocusRings(aShowFocusRings==UIStateChangeType_Set);}nsContentUtils::SetKeyboardIndicatorsOnRemoteChildren(GetOuterWindow(),aShowAccelerators,aShowFocusRings);}Element*nsPIDOMWindowOuter::GetFrameElementInternal()const{MOZ_ASSERT(IsOuterWindow());returnmFrameElement;}voidnsPIDOMWindowOuter::SetFrameElementInternal(Element*aFrameElement){MOZ_ASSERT(IsOuterWindow());mFrameElement=aFrameElement;}boolnsPIDOMWindowInner::AddAudioContext(AudioContext*aAudioContext){MOZ_ASSERT(IsInnerWindow());mAudioContexts.AppendElement(aAudioContext);// Return true if the context should be muted and false if not.nsIDocShell*docShell=GetDocShell();returndocShell&&!docShell->GetAllowMedia()&&!aAudioContext->IsOffline();}voidnsPIDOMWindowInner::RemoveAudioContext(AudioContext*aAudioContext){MOZ_ASSERT(IsInnerWindow());mAudioContexts.RemoveElement(aAudioContext);}voidnsPIDOMWindowInner::MuteAudioContexts(){MOZ_ASSERT(IsInnerWindow());for(uint32_ti=0;i<mAudioContexts.Length();++i){if(!mAudioContexts[i]->IsOffline()){mAudioContexts[i]->Mute();}}}voidnsPIDOMWindowInner::UnmuteAudioContexts(){MOZ_ASSERT(IsInnerWindow());for(uint32_ti=0;i<mAudioContexts.Length();++i){if(!mAudioContexts[i]->IsOffline()){mAudioContexts[i]->Unmute();}}}nsGlobalWindow*nsGlobalWindow::Window(){returnthis;}nsGlobalWindow*nsGlobalWindow::Self(){returnthis;}Navigator*nsGlobalWindow::Navigator(){MOZ_RELEASE_ASSERT(IsInnerWindow());if(!mNavigator){mNavigator=newmozilla::dom::Navigator(AsInner());}returnmNavigator;}nsIDOMNavigator*nsGlobalWindow::GetNavigator(){FORWARD_TO_INNER(GetNavigator,(),nullptr);returnNavigator();}nsScreen*nsGlobalWindow::GetScreen(ErrorResult&aError){MOZ_RELEASE_ASSERT(IsInnerWindow());if(!mScreen){mScreen=nsScreen::Create(AsInner());if(!mScreen){aError.Throw(NS_ERROR_UNEXPECTED);returnnullptr;}}returnmScreen;}nsIDOMScreen*nsGlobalWindow::GetScreen(){FORWARD_TO_INNER(GetScreen,(),nullptr);ErrorResultdummy;nsIDOMScreen*screen=GetScreen(dummy);dummy.SuppressException();returnscreen;}nsHistory*nsGlobalWindow::GetHistory(ErrorResult&aError){MOZ_RELEASE_ASSERT(IsInnerWindow());if(!mHistory){mHistory=newnsHistory(AsInner());}returnmHistory;}CustomElementRegistry*nsGlobalWindow::CustomElements(){MOZ_RELEASE_ASSERT(IsInnerWindow());if(!mCustomElements){mCustomElements=newCustomElementRegistry(AsInner());}returnmCustomElements;}Performance*nsPIDOMWindowInner::GetPerformance(){MOZ_ASSERT(IsInnerWindow());CreatePerformanceObjectIfNeeded();returnmPerformance;}Performance*nsGlobalWindow::GetPerformance(){returnAsInner()->GetPerformance();}voidnsPIDOMWindowInner::CreatePerformanceObjectIfNeeded(){MOZ_ASSERT(IsInnerWindow());if(mPerformance||!mDoc){return;}RefPtr<nsDOMNavigationTiming>timing=mDoc->GetNavigationTiming();nsCOMPtr<nsITimedChannel>timedChannel(do_QueryInterface(mDoc->GetChannel()));booltimingEnabled=false;if(!timedChannel||!NS_SUCCEEDED(timedChannel->GetTimingEnabled(&timingEnabled))||!timingEnabled){timedChannel=nullptr;}if(timing){mPerformance=Performance::CreateForMainThread(this,timing,timedChannel);}}boolnsPIDOMWindowInner::IsSecureContext()const{returnnsGlobalWindow::Cast(this)->IsSecureContext();}boolnsPIDOMWindowInner::IsSecureContextIfOpenerIgnored()const{returnnsGlobalWindow::Cast(this)->IsSecureContextIfOpenerIgnored();}voidnsPIDOMWindowInner::Suspend(){nsGlobalWindow::Cast(this)->Suspend();}voidnsPIDOMWindowInner::Resume(){nsGlobalWindow::Cast(this)->Resume();}voidnsPIDOMWindowInner::Freeze(){nsGlobalWindow::Cast(this)->Freeze();}voidnsPIDOMWindowInner::Thaw(){nsGlobalWindow::Cast(this)->Thaw();}voidnsPIDOMWindowInner::SyncStateFromParentWindow(){nsGlobalWindow::Cast(this)->SyncStateFromParentWindow();}boolnsPIDOMWindowInner::IsPlayingAudio(){RefPtr<AudioChannelService>acs=AudioChannelService::Get();if(!acs){returnfalse;}autoouter=GetOuterWindow();if(!outer){// We've been unlinked and are about to die. Not a good time to pretend to// be playing audio.returnfalse;}returnacs->IsWindowActive(outer);}boolnsPIDOMWindowInner::IsDocumentLoaded()const{returnmIsDocumentLoaded;}mozilla::dom::TimeoutManager&nsPIDOMWindowInner::TimeoutManager(){return*mTimeoutManager;}boolnsPIDOMWindowInner::IsRunningTimeout(){returnTimeoutManager().IsRunningTimeout();}voidnsPIDOMWindowInner::TryToCacheTopInnerWindow(){if(mHasTriedToCacheTopInnerWindow){return;}MOZ_ASSERT(!mInnerObjectsFreed);mHasTriedToCacheTopInnerWindow=true;nsGlobalWindow*window=nsGlobalWindow::Cast(AsInner());MOZ_ASSERT(window);if(nsCOMPtr<nsPIDOMWindowOuter>topOutter=window->GetScriptableTop()){mTopInnerWindow=topOutter->GetCurrentInnerWindow();}}voidnsPIDOMWindowInner::UpdateActiveIndexedDBTransactionCount(int32_taDelta){MOZ_ASSERT(NS_IsMainThread());if(aDelta==0){return;}TabGroup()->IndexedDBTransactionCounter()+=aDelta;}voidnsPIDOMWindowInner::UpdateActiveIndexedDBDatabaseCount(int32_taDelta){MOZ_ASSERT(NS_IsMainThread());if(aDelta==0){return;}// We count databases but not transactions because only active databases// could block throttling.uint32_t&counter=mTopInnerWindow?mTopInnerWindow->mNumOfIndexedDBDatabases:mNumOfIndexedDBDatabases;counter+=aDelta;TabGroup()->IndexedDBDatabaseCounter()+=aDelta;}boolnsPIDOMWindowInner::HasActiveIndexedDBDatabases(){MOZ_ASSERT(NS_IsMainThread());returnmTopInnerWindow?mTopInnerWindow->mNumOfIndexedDBDatabases>0:mNumOfIndexedDBDatabases>0;}voidnsPIDOMWindowOuter::MaybeActiveMediaComponents(){if(IsInnerWindow()){returnmOuterWindow->MaybeActiveMediaComponents();}if(mMediaSuspend!=nsISuspendedTypes::SUSPENDED_BLOCK){return;}MOZ_LOG(AudioChannelService::GetAudioChannelLog(),LogLevel::Debug,("nsPIDOMWindowOuter, MaybeActiveMediaComponents, ""resume the window from blocked, this = %p\n",this));SetMediaSuspend(nsISuspendedTypes::NONE_SUSPENDED);}SuspendTypesnsPIDOMWindowOuter::GetMediaSuspend()const{if(IsInnerWindow()){returnmOuterWindow->GetMediaSuspend();}returnmMediaSuspend;}voidnsPIDOMWindowOuter::SetMediaSuspend(SuspendTypesaSuspend){if(IsInnerWindow()){mOuterWindow->SetMediaSuspend(aSuspend);return;}if(!IsDisposableSuspend(aSuspend)){MaybeNotifyMediaResumedFromBlock(aSuspend);mMediaSuspend=aSuspend;}RefreshMediaElementsSuspend(aSuspend);}voidnsPIDOMWindowOuter::MaybeNotifyMediaResumedFromBlock(SuspendTypesaSuspend){if(mMediaSuspend==nsISuspendedTypes::SUSPENDED_BLOCK&&aSuspend==nsISuspendedTypes::NONE_SUSPENDED){RefPtr<AudioChannelService>service=AudioChannelService::GetOrCreate();if(service){service->NotifyMediaResumedFromBlock(GetOuterWindow());}}}boolnsPIDOMWindowOuter::GetAudioMuted()const{if(IsInnerWindow()){returnmOuterWindow->GetAudioMuted();}returnmAudioMuted;}voidnsPIDOMWindowOuter::SetAudioMuted(boolaMuted){if(IsInnerWindow()){mOuterWindow->SetAudioMuted(aMuted);return;}if(mAudioMuted==aMuted){return;}mAudioMuted=aMuted;RefreshMediaElementsVolume();}floatnsPIDOMWindowOuter::GetAudioVolume()const{if(IsInnerWindow()){returnmOuterWindow->GetAudioVolume();}returnmAudioVolume;}nsresultnsPIDOMWindowOuter::SetAudioVolume(floataVolume){if(IsInnerWindow()){returnmOuterWindow->SetAudioVolume(aVolume);}if(aVolume<0.0){returnNS_ERROR_DOM_INDEX_SIZE_ERR;}if(mAudioVolume==aVolume){returnNS_OK;}mAudioVolume=aVolume;RefreshMediaElementsVolume();returnNS_OK;}voidnsPIDOMWindowOuter::RefreshMediaElementsVolume(){RefPtr<AudioChannelService>service=AudioChannelService::GetOrCreate();if(service){service->RefreshAgentsVolume(GetOuterWindow());}}voidnsPIDOMWindowOuter::RefreshMediaElementsSuspend(SuspendTypesaSuspend){RefPtr<AudioChannelService>service=AudioChannelService::GetOrCreate();if(service){service->RefreshAgentsSuspend(GetOuterWindow(),aSuspend);}}boolnsPIDOMWindowOuter::IsDisposableSuspend(SuspendTypesaSuspend)const{return(aSuspend==nsISuspendedTypes::SUSPENDED_PAUSE_DISPOSABLE||aSuspend==nsISuspendedTypes::SUSPENDED_STOP_DISPOSABLE);}voidnsPIDOMWindowOuter::SetServiceWorkersTestingEnabled(boolaEnabled){// Devtools should only be setting this on the top level window. Its// ok if devtools clears the flag on clean up of nested windows, though.// It will have no affect.#ifdef DEBUGnsCOMPtr<nsPIDOMWindowOuter>topWindow=GetScriptableTop();MOZ_ASSERT_IF(aEnabled,this==topWindow);#endifmServiceWorkersTestingEnabled=aEnabled;}boolnsPIDOMWindowOuter::GetServiceWorkersTestingEnabled(){// Automatically get this setting from the top level window so that nested// iframes get the correct devtools setting.nsCOMPtr<nsPIDOMWindowOuter>topWindow=GetScriptableTop();if(!topWindow){returnfalse;}returntopWindow->mServiceWorkersTestingEnabled;}boolnsPIDOMWindowInner::GetAudioCaptured()const{MOZ_ASSERT(IsInnerWindow());returnmAudioCaptured;}nsresultnsPIDOMWindowInner::SetAudioCapture(boolaCapture){MOZ_ASSERT(IsInnerWindow());mAudioCaptured=aCapture;RefPtr<AudioChannelService>service=AudioChannelService::GetOrCreate();if(service){service->SetWindowAudioCaptured(GetOuterWindow(),mWindowID,aCapture);}returnNS_OK;}// nsISpeechSynthesisGetter#ifdef MOZ_WEBSPEECHSpeechSynthesis*nsGlobalWindow::GetSpeechSynthesis(ErrorResult&aError){MOZ_RELEASE_ASSERT(IsInnerWindow());if(!mSpeechSynthesis){mSpeechSynthesis=newSpeechSynthesis(AsInner());}returnmSpeechSynthesis;}boolnsGlobalWindow::HasActiveSpeechSynthesis(){MOZ_ASSERT(IsInnerWindow());if(mSpeechSynthesis){return!mSpeechSynthesis->HasEmptyQueue();}returnfalse;}#endifalready_AddRefed<nsPIDOMWindowOuter>nsGlobalWindow::GetParentOuter(){MOZ_RELEASE_ASSERT(IsOuterWindow());if(!mDocShell){returnnullptr;}nsCOMPtr<nsPIDOMWindowOuter>parent;if(mDocShell->GetIsMozBrowser()){parent=AsOuter();}else{parent=GetParent();}returnparent.forget();}already_AddRefed<nsPIDOMWindowOuter>nsGlobalWindow::GetParent(ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(GetParentOuter,(),aError,nullptr);}/** * GetScriptableParent is called when script reads window.parent. * * In contrast to GetRealParent, GetScriptableParent respects <iframe * mozbrowser> boundaries, so if |this| is contained by an <iframe * mozbrowser>, we will return |this| as its own parent. */nsPIDOMWindowOuter*nsGlobalWindow::GetScriptableParent(){FORWARD_TO_OUTER(GetScriptableParent,(),nullptr);nsCOMPtr<nsPIDOMWindowOuter>parent=GetParentOuter();returnparent.get();}/** * Behavies identically to GetScriptableParent extept that it returns null * if GetScriptableParent would return this window. */nsPIDOMWindowOuter*nsGlobalWindow::GetScriptableParentOrNull(){FORWARD_TO_OUTER(GetScriptableParentOrNull,(),nullptr);nsPIDOMWindowOuter*parent=GetScriptableParent();return(Cast(parent)==this)?nullptr:parent;}/** * nsPIDOMWindow::GetParent (when called from C++) is just a wrapper around * GetRealParent. */already_AddRefed<nsPIDOMWindowOuter>nsGlobalWindow::GetParent(){MOZ_ASSERT(IsOuterWindow());if(!mDocShell){returnnullptr;}nsCOMPtr<nsIDocShell>parent;mDocShell->GetSameTypeParentIgnoreBrowserBoundaries(getter_AddRefs(parent));if(parent){nsCOMPtr<nsPIDOMWindowOuter>win=parent->GetWindow();returnwin.forget();}nsCOMPtr<nsPIDOMWindowOuter>win(AsOuter());returnwin.forget();}staticnsresultGetTopImpl(nsGlobalWindow*aWin,nsPIDOMWindowOuter**aTop,boolaScriptable){*aTop=nullptr;// Walk up the parent chain.nsCOMPtr<nsPIDOMWindowOuter>prevParent=aWin->AsOuter();nsCOMPtr<nsPIDOMWindowOuter>parent=aWin->AsOuter();do{if(!parent){break;}prevParent=parent;nsCOMPtr<nsPIDOMWindowOuter>newParent;if(aScriptable){newParent=parent->GetScriptableParent();}else{newParent=parent->GetParent();}parent=newParent;}while(parent!=prevParent);if(parent){parent.swap(*aTop);}returnNS_OK;}/** * GetScriptableTop is called when script reads window.top. * * In contrast to GetRealTop, GetScriptableTop respects <iframe mozbrowser> * boundaries. If we encounter a window owned by an <iframe mozbrowser> while * walking up the window hierarchy, we'll stop and return that window. */nsPIDOMWindowOuter*nsGlobalWindow::GetScriptableTop(){FORWARD_TO_OUTER(GetScriptableTop,(),nullptr);nsCOMPtr<nsPIDOMWindowOuter>window;GetTopImpl(this,getter_AddRefs(window),/* aScriptable = */true);returnwindow.get();}already_AddRefed<nsPIDOMWindowOuter>nsGlobalWindow::GetTop(){MOZ_ASSERT(IsOuterWindow());nsCOMPtr<nsPIDOMWindowOuter>window;GetTopImpl(this,getter_AddRefs(window),/* aScriptable = */false);returnwindow.forget();}voidnsGlobalWindow::GetContentOuter(JSContext*aCx,JS::MutableHandle<JSObject*>aRetval,CallerTypeaCallerType,ErrorResult&aError){MOZ_RELEASE_ASSERT(IsOuterWindow());nsCOMPtr<nsPIDOMWindowOuter>content=GetContentInternal(aError,aCallerType);if(aError.Failed()){return;}if(content){JS::Rooted<JS::Value>val(aCx);aError=nsContentUtils::WrapNative(aCx,content,&val);if(aError.Failed()){return;}aRetval.set(&val.toObject());return;}aRetval.set(nullptr);return;}voidnsGlobalWindow::GetContent(JSContext*aCx,JS::MutableHandle<JSObject*>aRetval,CallerTypeaCallerType,ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(GetContentOuter,(aCx,aRetval,aCallerType,aError),aError,);}already_AddRefed<nsPIDOMWindowOuter>nsGlobalWindow::GetContentInternal(ErrorResult&aError,CallerTypeaCallerType){MOZ_ASSERT(IsOuterWindow());// First check for a named frame named "content"nsCOMPtr<nsPIDOMWindowOuter>domWindow=GetChildWindow(NS_LITERAL_STRING("content"));if(domWindow){returndomWindow.forget();}// If we're contained in <iframe mozbrowser>, then GetContent is the same as// window.top.if(mDocShell&&mDocShell->GetIsInMozBrowser()){returnGetTopOuter();}nsCOMPtr<nsIDocShellTreeItem>primaryContent;if(aCallerType!=CallerType::System){// If we're called by non-chrome code, make sure we don't return// the primary content window if the calling tab is hidden. In// such a case we return the same-type root in the hidden tab,// which is "good enough", for now.nsCOMPtr<nsIBaseWindow>baseWin(do_QueryInterface(mDocShell));if(baseWin){boolvisible=false;baseWin->GetVisibility(&visible);if(!visible){mDocShell->GetSameTypeRootTreeItem(getter_AddRefs(primaryContent));}}}if(!primaryContent){nsCOMPtr<nsIDocShellTreeOwner>treeOwner=GetTreeOwner();if(!treeOwner){aError.Throw(NS_ERROR_FAILURE);returnnullptr;}treeOwner->GetPrimaryContentShell(getter_AddRefs(primaryContent));}if(!primaryContent){returnnullptr;}domWindow=primaryContent->GetWindow();returndomWindow.forget();}MozSelfSupport*nsGlobalWindow::GetMozSelfSupport(ErrorResult&aError){MOZ_ASSERT(IsInnerWindow());if(mMozSelfSupport){returnmMozSelfSupport;}// We're called from JS and want to use out existing JSContext (and,// importantly, its compartment!) here.AutoJSContextcx;GlobalObjectglobal(cx,FastGetGlobalJSObject());mMozSelfSupport=MozSelfSupport::Constructor(global,cx,aError);returnmMozSelfSupport;}nsresultnsGlobalWindow::GetPrompter(nsIPrompt**aPrompt){if(IsInnerWindow()){nsGlobalWindow*outer=GetOuterWindowInternal();if(!outer){NS_WARNING("No outer window available!");returnNS_ERROR_NOT_INITIALIZED;}returnouter->GetPrompter(aPrompt);}if(!mDocShell)returnNS_ERROR_FAILURE;nsCOMPtr<nsIPrompt>prompter(do_GetInterface(mDocShell));NS_ENSURE_TRUE(prompter,NS_ERROR_NO_INTERFACE);prompter.forget(aPrompt);returnNS_OK;}BarProp*nsGlobalWindow::GetMenubar(ErrorResult&aError){MOZ_RELEASE_ASSERT(IsInnerWindow());if(!mMenubar){mMenubar=newMenubarProp(this);}returnmMenubar;}BarProp*nsGlobalWindow::GetToolbar(ErrorResult&aError){MOZ_RELEASE_ASSERT(IsInnerWindow());if(!mToolbar){mToolbar=newToolbarProp(this);}returnmToolbar;}BarProp*nsGlobalWindow::GetLocationbar(ErrorResult&aError){MOZ_RELEASE_ASSERT(IsInnerWindow());if(!mLocationbar){mLocationbar=newLocationbarProp(this);}returnmLocationbar;}BarProp*nsGlobalWindow::GetPersonalbar(ErrorResult&aError){MOZ_RELEASE_ASSERT(IsInnerWindow());if(!mPersonalbar){mPersonalbar=newPersonalbarProp(this);}returnmPersonalbar;}BarProp*nsGlobalWindow::GetStatusbar(ErrorResult&aError){MOZ_RELEASE_ASSERT(IsInnerWindow());if(!mStatusbar){mStatusbar=newStatusbarProp(this);}returnmStatusbar;}BarProp*nsGlobalWindow::GetScrollbars(ErrorResult&aError){MOZ_RELEASE_ASSERT(IsInnerWindow());if(!mScrollbars){mScrollbars=newScrollbarsProp(this);}returnmScrollbars;}boolnsGlobalWindow::GetClosedOuter(){MOZ_RELEASE_ASSERT(IsOuterWindow());// If someone called close(), or if we don't have a docshell, we're closed.returnmIsClosed||!mDocShell;}boolnsGlobalWindow::GetClosed(ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(GetClosedOuter,(),aError,false);}boolnsGlobalWindow::Closed(){MOZ_ASSERT(IsOuterWindow());returnGetClosedOuter();}nsDOMWindowList*nsGlobalWindow::GetWindowList(){MOZ_ASSERT(IsOuterWindow());if(!mFrames&&mDocShell){mFrames=newnsDOMWindowList(mDocShell);}returnmFrames;}already_AddRefed<nsIDOMWindowCollection>nsGlobalWindow::GetFrames(){FORWARD_TO_OUTER(GetFrames,(),nullptr);nsCOMPtr<nsIDOMWindowCollection>frames=GetWindowList();returnframes.forget();}already_AddRefed<nsPIDOMWindowOuter>nsGlobalWindow::IndexedGetterOuter(uint32_taIndex){MOZ_RELEASE_ASSERT(IsOuterWindow());nsDOMWindowList*windows=GetWindowList();NS_ENSURE_TRUE(windows,nullptr);returnwindows->IndexedGetter(aIndex);}already_AddRefed<nsPIDOMWindowOuter>nsGlobalWindow::IndexedGetter(uint32_taIndex){FORWARD_TO_OUTER(IndexedGetterOuter,(aIndex),nullptr);MOZ_CRASH();}boolnsGlobalWindow::DoResolve(JSContext*aCx,JS::Handle<JSObject*>aObj,JS::Handle<jsid>aId,JS::MutableHandle<JS::PropertyDescriptor>aDesc){MOZ_ASSERT(IsInnerWindow());// Note: Keep this in sync with MayResolve.// Note: The infallibleInit call in GlobalResolve depends on this check.if(!JSID_IS_STRING(aId)){returntrue;}boolfound;if(!WebIDLGlobalNameHash::DefineIfEnabled(aCx,aObj,aId,aDesc,&found)){returnfalse;}if(found){returntrue;}nsresultrv=nsWindowSH::GlobalResolve(this,aCx,aObj,aId,aDesc);if(NS_FAILED(rv)){returnThrow(aCx,rv);}returntrue;}/* static */boolnsGlobalWindow::MayResolve(jsidaId){// Note: This function does not fail and may not have any side-effects.// Note: Keep this in sync with DoResolve.if(!JSID_IS_STRING(aId)){returnfalse;}if(aId==XPCJSRuntime::Get()->GetStringID(XPCJSContext::IDX_COMPONENTS)){returntrue;}if(aId==XPCJSRuntime::Get()->GetStringID(XPCJSContext::IDX_CONTROLLERS)||aId==XPCJSRuntime::Get()->GetStringID(XPCJSContext::IDX_CONTROLLERS_CLASS)){// We only resolve .controllers/.Controllers in release builds and on non-chrome// windows, but let's not worry about any of that stuff.returntrue;}if(WebIDLGlobalNameHash::MayResolve(aId)){returntrue;}nsScriptNameSpaceManager*nameSpaceManager=PeekNameSpaceManager();if(!nameSpaceManager){// Really shouldn't happen. Fail safe.returntrue;}nsAutoStringname;AssignJSFlatString(name,JSID_TO_FLAT_STRING(aId));returnnameSpaceManager->LookupName(name);}voidnsGlobalWindow::GetOwnPropertyNames(JSContext*aCx,JS::AutoIdVector&aNames,boolaEnumerableOnly,ErrorResult&aRv){if(aEnumerableOnly){// The names we would return from here get defined on the window via one of// two codepaths. The ones coming from the WebIDLGlobalNameHash will end up// in the DefineConstructor function in BindingUtils, which always defines// things as non-enumerable. The ones coming from the script namespace// manager get defined by nsDOMClassInfo::PostCreatePrototype calling// ResolvePrototype and using the resulting descriptot to define the// property. ResolvePrototype always passes 0 to the FillPropertyDescriptor// for the property attributes, so all those are non-enumerable as well.//// So in the aEnumerableOnly case we have nothing to do.return;}MOZ_ASSERT(IsInnerWindow());// "Components" is marked as enumerable but only resolved on demand :-/.//aNames.AppendElement(NS_LITERAL_STRING("Components"));nsScriptNameSpaceManager*nameSpaceManager=GetNameSpaceManager();if(nameSpaceManager){JS::Rooted<JSObject*>wrapper(aCx,GetWrapper());// There are actually two ways we can get called here: For normal// enumeration or for Xray enumeration. In the latter case, we want to// return all possible WebIDL names, because we don't really support// deleting these names off our Xray; trying to resolve them will just make// them come back. In the former case, we want to avoid returning deleted// names. But the JS engine already knows about the non-deleted// already-resolved names, so we can just return the so-far-unresolved ones.//// We can tell which case we're in by whether aCx is in our wrapper's// compartment. If not, we're in the Xray case.WebIDLGlobalNameHash::NameTypenameType=js::IsObjectInContextCompartment(wrapper,aCx)?WebIDLGlobalNameHash::UnresolvedNamesOnly:WebIDLGlobalNameHash::AllNames;if(!WebIDLGlobalNameHash::GetNames(aCx,wrapper,nameType,aNames)){aRv.NoteJSContextException(aCx);}for(autoi=nameSpaceManager->GlobalNameIter();!i.Done();i.Next()){constGlobalNameMapEntry*entry=i.Get();if(nsWindowSH::NameStructEnabled(aCx,this,entry->mKey,entry->mGlobalName)){// Just append all of these; even if they get deleted our resolve hook// just goes ahead and recreates them.JSString*str=JS_AtomizeUCStringN(aCx,entry->mKey.BeginReading(),entry->mKey.Length());if(!str||!aNames.append(NON_INTEGER_ATOM_TO_JSID(str))){aRv.NoteJSContextException(aCx);return;}}}}}/* static */boolnsGlobalWindow::IsPrivilegedChromeWindow(JSContext*aCx,JSObject*aObj){// For now, have to deal with XPConnect objects here.returnxpc::WindowOrNull(aObj)->IsChromeWindow()&&nsContentUtils::ObjectPrincipal(aObj)==nsContentUtils::GetSystemPrincipal();}/* static */boolnsGlobalWindow::IsShowModalDialogEnabled(JSContext*,JSObject*){staticboolsAddedPrefCache=false;staticboolsIsDisabled;staticconstcharsShowModalDialogPref[]="dom.disable_window_showModalDialog";if(!sAddedPrefCache){Preferences::AddBoolVarCache(&sIsDisabled,sShowModalDialogPref,false);sAddedPrefCache=true;}return!sIsDisabled&&!XRE_IsContentProcess();}/* static */boolnsGlobalWindow::IsRequestIdleCallbackEnabled(JSContext*aCx,JSObject*aObj){// The requestIdleCallback should always be enabled for system code.returnnsContentUtils::RequestIdleCallbackEnabled()||nsContentUtils::IsSystemCaller(aCx);}nsIDOMOfflineResourceList*nsGlobalWindow::GetApplicationCache(ErrorResult&aError){MOZ_RELEASE_ASSERT(IsInnerWindow());if(!mApplicationCache){nsCOMPtr<nsIWebNavigation>webNav(do_QueryInterface(GetDocShell()));if(!webNav||!mDoc){aError.Throw(NS_ERROR_FAILURE);returnnullptr;}nsCOMPtr<nsIURI>uri;aError=webNav->GetCurrentURI(getter_AddRefs(uri));if(aError.Failed()){returnnullptr;}nsCOMPtr<nsIURI>manifestURI;nsContentUtils::GetOfflineAppManifest(mDoc,getter_AddRefs(manifestURI));RefPtr<nsDOMOfflineResourceList>applicationCache=newnsDOMOfflineResourceList(manifestURI,uri,mDoc->NodePrincipal(),AsInner());applicationCache->Init();mApplicationCache=applicationCache;}returnmApplicationCache;}already_AddRefed<nsIDOMOfflineResourceList>nsGlobalWindow::GetApplicationCache(){FORWARD_TO_INNER(GetApplicationCache,(),nullptr);ErrorResultdummy;nsCOMPtr<nsIDOMOfflineResourceList>applicationCache=GetApplicationCache(dummy);dummy.SuppressException();returnapplicationCache.forget();}Crypto*nsGlobalWindow::GetCrypto(ErrorResult&aError){MOZ_RELEASE_ASSERT(IsInnerWindow());if(!mCrypto){mCrypto=newCrypto();mCrypto->Init(this);}returnmCrypto;}mozilla::dom::U2F*nsGlobalWindow::GetU2f(ErrorResult&aError){MOZ_RELEASE_ASSERT(IsInnerWindow());if(!mU2F){RefPtr<U2F>u2f=newU2F();u2f->Init(AsInner(),aError);if(NS_WARN_IF(aError.Failed())){returnnullptr;}mU2F=u2f;}returnmU2F;}nsIControllers*nsGlobalWindow::GetControllersOuter(ErrorResult&aError){MOZ_RELEASE_ASSERT(IsOuterWindow());if(!mControllers){nsresultrv;mControllers=do_CreateInstance(kXULControllersCID,&rv);if(NS_FAILED(rv)){aError.Throw(rv);returnnullptr;}// Add in the default controllernsCOMPtr<nsIController>controller=do_CreateInstance(NS_WINDOWCONTROLLER_CONTRACTID,&rv);if(NS_FAILED(rv)){aError.Throw(rv);returnnullptr;}mControllers->InsertControllerAt(0,controller);nsCOMPtr<nsIControllerContext>controllerContext=do_QueryInterface(controller);if(!controllerContext){aError.Throw(NS_ERROR_FAILURE);returnnullptr;}controllerContext->SetCommandContext(static_cast<nsIDOMWindow*>(this));}returnmControllers;}nsIControllers*nsGlobalWindow::GetControllers(ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(GetControllersOuter,(aError),aError,nullptr);}nsresultnsGlobalWindow::GetControllers(nsIControllers**aResult){FORWARD_TO_INNER(GetControllers,(aResult),NS_ERROR_UNEXPECTED);ErrorResultrv;nsCOMPtr<nsIControllers>controllers=GetControllers(rv);controllers.forget(aResult);returnrv.StealNSResult();}nsPIDOMWindowOuter*nsGlobalWindow::GetSanitizedOpener(nsPIDOMWindowOuter*aOpener){if(!aOpener){returnnullptr;}nsGlobalWindow*win=nsGlobalWindow::Cast(aOpener);// First, ensure that we're not handing back a chrome window to content:if(win->IsChromeWindow()){returnnullptr;}// We don't want to reveal the opener if the opener is a mail window,// because opener can be used to spoof the contents of a message (bug 105050).// So, we look in the opener's root docshell to see if it's a mail window.nsCOMPtr<nsIDocShell>openerDocShell=aOpener->GetDocShell();if(openerDocShell){nsCOMPtr<nsIDocShellTreeItem>openerRootItem;openerDocShell->GetRootTreeItem(getter_AddRefs(openerRootItem));nsCOMPtr<nsIDocShell>openerRootDocShell(do_QueryInterface(openerRootItem));if(openerRootDocShell){uint32_tappType;nsresultrv=openerRootDocShell->GetAppType(&appType);if(NS_SUCCEEDED(rv)&&appType!=nsIDocShell::APP_TYPE_MAIL){returnaOpener;}}}returnnullptr;}nsPIDOMWindowOuter*nsGlobalWindow::GetOpenerWindowOuter(){MOZ_RELEASE_ASSERT(IsOuterWindow());nsCOMPtr<nsPIDOMWindowOuter>opener=do_QueryReferent(mOpener);if(!opener){returnnullptr;}// First, check if we were called from a privileged chrome scriptif(nsContentUtils::LegacyIsCallerChromeOrNativeCode()){// Catch the case where we're chrome but the opener is not...if(GetPrincipal()==nsContentUtils::GetSystemPrincipal()&&nsGlobalWindow::Cast(opener)->GetPrincipal()!=nsContentUtils::GetSystemPrincipal()){returnnullptr;}returnopener;}returnGetSanitizedOpener(opener);}nsPIDOMWindowOuter*nsGlobalWindow::GetOpenerWindow(ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(GetOpenerWindowOuter,(),aError,nullptr);}voidnsGlobalWindow::GetOpener(JSContext*aCx,JS::MutableHandle<JS::Value>aRetval,ErrorResult&aError){MOZ_ASSERT(IsInnerWindow());nsCOMPtr<nsPIDOMWindowOuter>opener=GetOpenerWindow(aError);if(aError.Failed()||!opener){aRetval.setNull();return;}aError=nsContentUtils::WrapNative(aCx,opener,aRetval);}already_AddRefed<nsPIDOMWindowOuter>nsGlobalWindow::GetOpener(){FORWARD_TO_OUTER(GetOpener,(),nullptr);nsCOMPtr<nsPIDOMWindowOuter>opener=GetOpenerWindowOuter();returnopener.forget();}voidnsGlobalWindow::SetOpener(JSContext*aCx,JS::Handle<JS::Value>aOpener,ErrorResult&aError){// Check if we were called from a privileged chrome script. If not, and if// aOpener is not null, just define aOpener on our inner window's JS object,// wrapped into the current compartment so that for Xrays we define on the// Xray expando object, but don't set it on the outer window, so that it'll// get reset on navigation. This is just like replaceable properties, but// we're not quite readonly.if(!aOpener.isNull()&&!nsContentUtils::IsCallerChrome()){RedefineProperty(aCx,"opener",aOpener,aError);return;}if(!aOpener.isObjectOrNull()){// Chrome code trying to set some random value as openeraError.Throw(NS_ERROR_INVALID_ARG);return;}nsPIDOMWindowInner*win=nullptr;if(aOpener.isObject()){JSObject*unwrapped=js::CheckedUnwrap(&aOpener.toObject(),/* stopAtWindowProxy = */false);if(!unwrapped){aError.Throw(NS_ERROR_DOM_SECURITY_ERR);return;}auto*globalWindow=xpc::WindowOrNull(unwrapped);if(!globalWindow){// Wasn't a windowaError.Throw(NS_ERROR_INVALID_ARG);return;}win=globalWindow->AsInner();}nsPIDOMWindowOuter*outer=nullptr;if(win){if(!win->IsCurrentInnerWindow()){aError.Throw(NS_ERROR_FAILURE);return;}outer=win->GetOuterWindow();}SetOpenerWindow(outer,false);}voidnsGlobalWindow::GetStatusOuter(nsAString&aStatus){MOZ_RELEASE_ASSERT(IsOuterWindow());aStatus=mStatus;}voidnsGlobalWindow::GetStatus(nsAString&aStatus,ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(GetStatusOuter,(aStatus),aError,);}voidnsGlobalWindow::SetStatusOuter(constnsAString&aStatus){MOZ_RELEASE_ASSERT(IsOuterWindow());mStatus=aStatus;/* * If caller is not chrome and dom.disable_window_status_change is true, * prevent propagating window.status to the UI by exiting early */if(!CanSetProperty("dom.disable_window_status_change")){return;}nsCOMPtr<nsIWebBrowserChrome>browserChrome=GetWebBrowserChrome();if(browserChrome){browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_SCRIPT,PromiseFlatString(aStatus).get());}}voidnsGlobalWindow::SetStatus(constnsAString&aStatus,ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(SetStatusOuter,(aStatus),aError,);}voidnsGlobalWindow::GetNameOuter(nsAString&aName){MOZ_RELEASE_ASSERT(IsOuterWindow());if(mDocShell){mDocShell->GetName(aName);}}voidnsGlobalWindow::GetName(nsAString&aName,ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(GetNameOuter,(aName),aError,);}voidnsGlobalWindow::SetNameOuter(constnsAString&aName,mozilla::ErrorResult&aError){MOZ_RELEASE_ASSERT(IsOuterWindow());if(mDocShell){aError=mDocShell->SetName(aName);}}voidnsGlobalWindow::SetName(constnsAString&aName,mozilla::ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(SetNameOuter,(aName,aError),aError,);}// Helper functions used by many methods below.int32_tnsGlobalWindow::DevToCSSIntPixels(int32_tpx){if(!mDocShell)returnpx;// assume 1:1RefPtr<nsPresContext>presContext;mDocShell->GetPresContext(getter_AddRefs(presContext));if(!presContext)returnpx;returnpresContext->DevPixelsToIntCSSPixels(px);}int32_tnsGlobalWindow::CSSToDevIntPixels(int32_tpx){if(!mDocShell)returnpx;// assume 1:1RefPtr<nsPresContext>presContext;mDocShell->GetPresContext(getter_AddRefs(presContext));if(!presContext)returnpx;returnpresContext->CSSPixelsToDevPixels(px);}nsIntSizensGlobalWindow::DevToCSSIntPixels(nsIntSizepx){if(!mDocShell)returnpx;// assume 1:1RefPtr<nsPresContext>presContext;mDocShell->GetPresContext(getter_AddRefs(presContext));if(!presContext)returnpx;returnnsIntSize(presContext->DevPixelsToIntCSSPixels(px.width),presContext->DevPixelsToIntCSSPixels(px.height));}nsIntSizensGlobalWindow::CSSToDevIntPixels(nsIntSizepx){if(!mDocShell)returnpx;// assume 1:1RefPtr<nsPresContext>presContext;mDocShell->GetPresContext(getter_AddRefs(presContext));if(!presContext)returnpx;returnnsIntSize(presContext->CSSPixelsToDevPixels(px.width),presContext->CSSPixelsToDevPixels(px.height));}nsresultnsGlobalWindow::GetInnerSize(CSSIntSize&aSize){MOZ_ASSERT(IsOuterWindow());EnsureSizeAndPositionUpToDate();NS_ENSURE_STATE(mDocShell);RefPtr<nsPresContext>presContext;mDocShell->GetPresContext(getter_AddRefs(presContext));RefPtr<nsIPresShell>presShell=mDocShell->GetPresShell();if(!presContext||!presShell){aSize=CSSIntSize(0,0);returnNS_OK;}/* * On platforms with resolution-based zooming, the CSS viewport * and visual viewport may not be the same. The inner size should * be the visual viewport, but we fall back to the CSS viewport * if it is not set. */if(presShell->IsScrollPositionClampingScrollPortSizeSet()){aSize=CSSIntRect::FromAppUnitsRounded(presShell->GetScrollPositionClampingScrollPortSize());}else{RefPtr<nsViewManager>viewManager=presShell->GetViewManager();if(viewManager){viewManager->FlushDelayedResize(false);}aSize=CSSIntRect::FromAppUnitsRounded(presContext->GetVisibleArea().Size());}returnNS_OK;}int32_tnsGlobalWindow::GetInnerWidthOuter(ErrorResult&aError){MOZ_RELEASE_ASSERT(IsOuterWindow());CSSIntSizesize;aError=GetInnerSize(size);returnsize.width;}int32_tnsGlobalWindow::GetInnerWidth(CallerTypeaCallerType,ErrorResult&aError){// We ignore aCallerType; we only have that argument because some other things// called by GetReplaceableWindowCoord need it. If this ever changes, fix// nsresult nsGlobalWindow::GetInnerWidth(int32_t* aInnerWidth)// to actually take a useful CallerType and pass it in here.FORWARD_TO_OUTER_OR_THROW(GetInnerWidthOuter,(aError),aError,0);}voidnsGlobalWindow::GetInnerWidth(JSContext*aCx,JS::MutableHandle<JS::Value>aValue,CallerTypeaCallerType,ErrorResult&aError){GetReplaceableWindowCoord(aCx,&nsGlobalWindow::GetInnerWidth,aValue,aCallerType,aError);}nsresultnsGlobalWindow::GetInnerWidth(int32_t*aInnerWidth){FORWARD_TO_INNER(GetInnerWidth,(aInnerWidth),NS_ERROR_UNEXPECTED);ErrorResultrv;// Callee doesn't care about the caller type, but play it safe.*aInnerWidth=GetInnerWidth(CallerType::NonSystem,rv);returnrv.StealNSResult();}voidnsGlobalWindow::SetInnerWidthOuter(int32_taInnerWidth,CallerTypeaCallerType,ErrorResult&aError){MOZ_RELEASE_ASSERT(IsOuterWindow());if(!mDocShell){aError.Throw(NS_ERROR_UNEXPECTED);return;}CheckSecurityWidthAndHeight(&aInnerWidth,nullptr,aCallerType);RefPtr<nsIPresShell>presShell=mDocShell->GetPresShell();if(presShell&&presShell->GetIsViewportOverridden()){nscoordheight=0;RefPtr<nsPresContext>presContext;presContext=presShell->GetPresContext();nsRectshellArea=presContext->GetVisibleArea();height=shellArea.height;SetCSSViewportWidthAndHeight(nsPresContext::CSSPixelsToAppUnits(aInnerWidth),height);return;}int32_theight=0;int32_tunused=0;nsCOMPtr<nsIBaseWindow>docShellAsWin(do_QueryInterface(mDocShell));docShellAsWin->GetSize(&unused,&height);aError=SetDocShellWidthAndHeight(CSSToDevIntPixels(aInnerWidth),height);}voidnsGlobalWindow::SetInnerWidth(int32_taInnerWidth,CallerTypeaCallerType,ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(SetInnerWidthOuter,(aInnerWidth,aCallerType,aError),aError,);}voidnsGlobalWindow::SetInnerWidth(JSContext*aCx,JS::Handle<JS::Value>aValue,CallerTypeaCallerType,ErrorResult&aError){SetReplaceableWindowCoord(aCx,&nsGlobalWindow::SetInnerWidth,aValue,"innerWidth",aCallerType,aError);}int32_tnsGlobalWindow::GetInnerHeightOuter(ErrorResult&aError){MOZ_RELEASE_ASSERT(IsOuterWindow());CSSIntSizesize;aError=GetInnerSize(size);returnsize.height;}int32_tnsGlobalWindow::GetInnerHeight(CallerTypeaCallerType,ErrorResult&aError){// We ignore aCallerType; we only have that argument because some other things// called by GetReplaceableWindowCoord need it. If this ever changes, fix// nsresult nsGlobalWindow::GetInnerHeight(int32_t* aInnerWidth)// to actually take a useful CallerType and pass it in here.FORWARD_TO_OUTER_OR_THROW(GetInnerHeightOuter,(aError),aError,0);}voidnsGlobalWindow::GetInnerHeight(JSContext*aCx,JS::MutableHandle<JS::Value>aValue,CallerTypeaCallerType,ErrorResult&aError){GetReplaceableWindowCoord(aCx,&nsGlobalWindow::GetInnerHeight,aValue,aCallerType,aError);}nsresultnsGlobalWindow::GetInnerHeight(int32_t*aInnerHeight){FORWARD_TO_INNER(GetInnerHeight,(aInnerHeight),NS_ERROR_UNEXPECTED);ErrorResultrv;// Callee doesn't care about the caller type, but play it safe.*aInnerHeight=GetInnerHeight(CallerType::NonSystem,rv);returnrv.StealNSResult();}voidnsGlobalWindow::SetInnerHeightOuter(int32_taInnerHeight,CallerTypeaCallerType,ErrorResult&aError){MOZ_RELEASE_ASSERT(IsOuterWindow());if(!mDocShell){aError.Throw(NS_ERROR_UNEXPECTED);return;}RefPtr<nsIPresShell>presShell=mDocShell->GetPresShell();if(presShell&&presShell->GetIsViewportOverridden()){RefPtr<nsPresContext>presContext;presContext=presShell->GetPresContext();nsRectshellArea=presContext->GetVisibleArea();nscoordheight=aInnerHeight;nscoordwidth=shellArea.width;CheckSecurityWidthAndHeight(nullptr,&height,aCallerType);SetCSSViewportWidthAndHeight(width,nsPresContext::CSSPixelsToAppUnits(height));return;}int32_theight=0;int32_twidth=0;nsCOMPtr<nsIBaseWindow>docShellAsWin(do_QueryInterface(mDocShell));docShellAsWin->GetSize(&width,&height);CheckSecurityWidthAndHeight(nullptr,&aInnerHeight,aCallerType);aError=SetDocShellWidthAndHeight(width,CSSToDevIntPixels(aInnerHeight));}voidnsGlobalWindow::SetInnerHeight(int32_taInnerHeight,CallerTypeaCallerType,ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(SetInnerHeightOuter,(aInnerHeight,aCallerType,aError),aError,);}voidnsGlobalWindow::SetInnerHeight(JSContext*aCx,JS::Handle<JS::Value>aValue,CallerTypeaCallerType,ErrorResult&aError){SetReplaceableWindowCoord(aCx,&nsGlobalWindow::SetInnerHeight,aValue,"innerHeight",aCallerType,aError);}nsIntSizensGlobalWindow::GetOuterSize(CallerTypeaCallerType,ErrorResult&aError){MOZ_ASSERT(IsOuterWindow());if(nsContentUtils::ResistFingerprinting(aCallerType)){CSSIntSizesize;aError=GetInnerSize(size);returnnsIntSize(size.width,size.height);}nsCOMPtr<nsIBaseWindow>treeOwnerAsWin=GetTreeOwnerWindow();if(!treeOwnerAsWin){aError.Throw(NS_ERROR_FAILURE);returnnsIntSize(0,0);}nsIntSizesizeDevPixels;aError=treeOwnerAsWin->GetSize(&sizeDevPixels.width,&sizeDevPixels.height);if(aError.Failed()){returnnsIntSize();}returnDevToCSSIntPixels(sizeDevPixels);}int32_tnsGlobalWindow::GetOuterWidthOuter(CallerTypeaCallerType,ErrorResult&aError){MOZ_RELEASE_ASSERT(IsOuterWindow());returnGetOuterSize(aCallerType,aError).width;}int32_tnsGlobalWindow::GetOuterWidth(CallerTypeaCallerType,ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(GetOuterWidthOuter,(aCallerType,aError),aError,0);}voidnsGlobalWindow::GetOuterWidth(JSContext*aCx,JS::MutableHandle<JS::Value>aValue,CallerTypeaCallerType,ErrorResult&aError){GetReplaceableWindowCoord(aCx,&nsGlobalWindow::GetOuterWidth,aValue,aCallerType,aError);}int32_tnsGlobalWindow::GetOuterHeightOuter(CallerTypeaCallerType,ErrorResult&aError){MOZ_RELEASE_ASSERT(IsOuterWindow());returnGetOuterSize(aCallerType,aError).height;}int32_tnsGlobalWindow::GetOuterHeight(CallerTypeaCallerType,ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(GetOuterHeightOuter,(aCallerType,aError),aError,0);}voidnsGlobalWindow::GetOuterHeight(JSContext*aCx,JS::MutableHandle<JS::Value>aValue,CallerTypeaCallerType,ErrorResult&aError){GetReplaceableWindowCoord(aCx,&nsGlobalWindow::GetOuterHeight,aValue,aCallerType,aError);}voidnsGlobalWindow::SetOuterSize(int32_taLengthCSSPixels,boolaIsWidth,CallerTypeaCallerType,ErrorResult&aError){MOZ_ASSERT(IsOuterWindow());nsCOMPtr<nsIBaseWindow>treeOwnerAsWin=GetTreeOwnerWindow();if(!treeOwnerAsWin){aError.Throw(NS_ERROR_FAILURE);return;}CheckSecurityWidthAndHeight(aIsWidth?&aLengthCSSPixels:nullptr,aIsWidth?nullptr:&aLengthCSSPixels,aCallerType);int32_twidth,height;aError=treeOwnerAsWin->GetSize(&width,&height);if(aError.Failed()){return;}int32_tlengthDevPixels=CSSToDevIntPixels(aLengthCSSPixels);if(aIsWidth){width=lengthDevPixels;}else{height=lengthDevPixels;}aError=treeOwnerAsWin->SetSize(width,height,true);CheckForDPIChange();}voidnsGlobalWindow::SetOuterWidthOuter(int32_taOuterWidth,CallerTypeaCallerType,ErrorResult&aError){MOZ_RELEASE_ASSERT(IsOuterWindow());SetOuterSize(aOuterWidth,true,aCallerType,aError);}voidnsGlobalWindow::SetOuterWidth(int32_taOuterWidth,CallerTypeaCallerType,ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(SetOuterWidthOuter,(aOuterWidth,aCallerType,aError),aError,);}voidnsGlobalWindow::SetOuterWidth(JSContext*aCx,JS::Handle<JS::Value>aValue,CallerTypeaCallerType,ErrorResult&aError){SetReplaceableWindowCoord(aCx,&nsGlobalWindow::SetOuterWidth,aValue,"outerWidth",aCallerType,aError);}voidnsGlobalWindow::SetOuterHeightOuter(int32_taOuterHeight,CallerTypeaCallerType,ErrorResult&aError){MOZ_RELEASE_ASSERT(IsOuterWindow());SetOuterSize(aOuterHeight,false,aCallerType,aError);}voidnsGlobalWindow::SetOuterHeight(int32_taOuterHeight,CallerTypeaCallerType,ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(SetOuterHeightOuter,(aOuterHeight,aCallerType,aError),aError,);}voidnsGlobalWindow::SetOuterHeight(JSContext*aCx,JS::Handle<JS::Value>aValue,CallerTypeaCallerType,ErrorResult&aError){SetReplaceableWindowCoord(aCx,&nsGlobalWindow::SetOuterHeight,aValue,"outerHeight",aCallerType,aError);}CSSIntPointnsGlobalWindow::GetScreenXY(CallerTypeaCallerType,ErrorResult&aError){MOZ_ASSERT(IsOuterWindow());// When resisting fingerprinting, always return (0,0)if(nsContentUtils::ResistFingerprinting(aCallerType)){returnCSSIntPoint(0,0);}nsCOMPtr<nsIBaseWindow>treeOwnerAsWin=GetTreeOwnerWindow();if(!treeOwnerAsWin){aError.Throw(NS_ERROR_FAILURE);returnCSSIntPoint(0,0);}int32_tx=0,y=0;aError=treeOwnerAsWin->GetPosition(&x,&y);// LayoutDevice px valuesRefPtr<nsPresContext>presContext;mDocShell->GetPresContext(getter_AddRefs(presContext));if(!presContext){returnCSSIntPoint(x,y);}// Find the global desktop coordinate of the top-left of the screen.// We'll use this as a "fake origin" when converting to CSS px units,// to avoid overlapping coordinates in cases such as a hi-dpi screen// placed to the right of a lo-dpi screen on Windows. (Instead, there// may be "gaps" in the resulting CSS px coordinates in some cases.)nsDeviceContext*dc=presContext->DeviceContext();nsRectscreenRect;dc->GetRect(screenRect);LayoutDeviceRectscreenRectDev=LayoutDevicePixel::FromAppUnits(screenRect,dc->AppUnitsPerDevPixel());DesktopToLayoutDeviceScalescale=dc->GetDesktopToDeviceScale();DesktopRectscreenRectDesk=screenRectDev/scale;CSSPointcssPt=LayoutDevicePoint(x-screenRectDev.x,y-screenRectDev.y)/presContext->CSSToDevPixelScale();cssPt.x+=screenRectDesk.x;cssPt.y+=screenRectDesk.y;returnCSSIntPoint(NSToIntRound(cssPt.x),NSToIntRound(cssPt.y));}int32_tnsGlobalWindow::GetScreenXOuter(CallerTypeaCallerType,ErrorResult&aError){MOZ_RELEASE_ASSERT(IsOuterWindow());returnGetScreenXY(aCallerType,aError).x;}int32_tnsGlobalWindow::GetScreenX(CallerTypeaCallerType,ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(GetScreenXOuter,(aCallerType,aError),aError,0);}voidnsGlobalWindow::GetScreenX(JSContext*aCx,JS::MutableHandle<JS::Value>aValue,CallerTypeaCallerType,ErrorResult&aError){GetReplaceableWindowCoord(aCx,&nsGlobalWindow::GetScreenX,aValue,aCallerType,aError);}nsRectnsGlobalWindow::GetInnerScreenRect(){MOZ_ASSERT(IsOuterWindow());if(!mDocShell){returnnsRect();}EnsureSizeAndPositionUpToDate();if(!mDocShell){returnnsRect();}nsCOMPtr<nsIPresShell>presShell=mDocShell->GetPresShell();if(!presShell){returnnsRect();}nsIFrame*rootFrame=presShell->GetRootFrame();if(!rootFrame){returnnsRect();}returnrootFrame->GetScreenRectInAppUnits();}floatnsGlobalWindow::GetMozInnerScreenXOuter(CallerTypeaCallerType){MOZ_RELEASE_ASSERT(IsOuterWindow());// When resisting fingerprinting, always return 0.if(nsContentUtils::ResistFingerprinting(aCallerType)){return0.0;}nsRectr=GetInnerScreenRect();returnnsPresContext::AppUnitsToFloatCSSPixels(r.x);}floatnsGlobalWindow::GetMozInnerScreenX(CallerTypeaCallerType,ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(GetMozInnerScreenXOuter,(aCallerType),aError,0);}floatnsGlobalWindow::GetMozInnerScreenYOuter(CallerTypeaCallerType){MOZ_RELEASE_ASSERT(IsOuterWindow());// Return 0 to prevent fingerprinting.if(nsContentUtils::ResistFingerprinting(aCallerType)){return0.0;}nsRectr=GetInnerScreenRect();returnnsPresContext::AppUnitsToFloatCSSPixels(r.y);}floatnsGlobalWindow::GetMozInnerScreenY(CallerTypeaCallerType,ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(GetMozInnerScreenYOuter,(aCallerType),aError,0);}floatnsGlobalWindow::GetDevicePixelRatioOuter(CallerTypeaCallerType){MOZ_RELEASE_ASSERT(IsOuterWindow());if(!mDocShell){return1.0;}RefPtr<nsPresContext>presContext;mDocShell->GetPresContext(getter_AddRefs(presContext));if(!presContext){return1.0;}if(nsContentUtils::ResistFingerprinting(aCallerType)){return1.0;}floatoverrideDPPX=presContext->GetOverrideDPPX();if(overrideDPPX>0){returnoverrideDPPX;}returnfloat(nsPresContext::AppUnitsPerCSSPixel())/presContext->AppUnitsPerDevPixel();}floatnsGlobalWindow::GetDevicePixelRatio(CallerTypeaCallerType,ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(GetDevicePixelRatioOuter,(aCallerType),aError,0.0);}floatnsPIDOMWindowOuter::GetDevicePixelRatio(CallerTypeaCallerType){returnnsGlobalWindow::Cast(this)->GetDevicePixelRatioOuter(aCallerType);}uint64_tnsGlobalWindow::GetMozPaintCountOuter(){MOZ_RELEASE_ASSERT(IsOuterWindow());if(!mDocShell){return0;}nsCOMPtr<nsIPresShell>presShell=mDocShell->GetPresShell();returnpresShell?presShell->GetPaintCount():0;}uint64_tnsGlobalWindow::GetMozPaintCount(ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(GetMozPaintCountOuter,(),aError,0);}int32_tnsGlobalWindow::RequestAnimationFrame(FrameRequestCallback&aCallback,ErrorResult&aError){MOZ_RELEASE_ASSERT(IsInnerWindow());if(!mDoc){return0;}if(GetWrapperPreserveColor()){js::NotifyAnimationActivity(GetWrapperPreserveColor());}int32_thandle;aError=mDoc->ScheduleFrameRequestCallback(aCallback,&handle);returnhandle;}voidnsGlobalWindow::CancelAnimationFrame(int32_taHandle,ErrorResult&aError){MOZ_RELEASE_ASSERT(IsInnerWindow());if(!mDoc){return;}mDoc->CancelFrameRequestCallback(aHandle);}already_AddRefed<MediaQueryList>nsGlobalWindow::MatchMediaOuter(constnsAString&aMediaQueryList){MOZ_RELEASE_ASSERT(IsOuterWindow());if(!mDoc){returnnullptr;}returnmDoc->MatchMedia(aMediaQueryList);}already_AddRefed<MediaQueryList>nsGlobalWindow::MatchMedia(constnsAString&aMediaQueryList,ErrorResult&aError){// FIXME: This whole forward-to-outer and then get a pres// shell/context off the docshell dance is sort of silly; it'd make// more sense to forward to the inner, but it's what everyone else// (GetSelection, GetScrollXY, etc.) does around here.FORWARD_TO_OUTER_OR_THROW(MatchMediaOuter,(aMediaQueryList),aError,nullptr);}voidnsGlobalWindow::SetScreenXOuter(int32_taScreenX,CallerTypeaCallerType,ErrorResult&aError){MOZ_RELEASE_ASSERT(IsOuterWindow());nsCOMPtr<nsIBaseWindow>treeOwnerAsWin=GetTreeOwnerWindow();if(!treeOwnerAsWin){aError.Throw(NS_ERROR_FAILURE);return;}int32_tx,y;aError=treeOwnerAsWin->GetPosition(&x,&y);if(aError.Failed()){return;}CheckSecurityLeftAndTop(&aScreenX,nullptr,aCallerType);x=CSSToDevIntPixels(aScreenX);aError=treeOwnerAsWin->SetPosition(x,y);CheckForDPIChange();}voidnsGlobalWindow::SetScreenX(int32_taScreenX,CallerTypeaCallerType,ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(SetScreenXOuter,(aScreenX,aCallerType,aError),aError,);}voidnsGlobalWindow::SetScreenX(JSContext*aCx,JS::Handle<JS::Value>aValue,CallerTypeaCallerType,ErrorResult&aError){SetReplaceableWindowCoord(aCx,&nsGlobalWindow::SetScreenX,aValue,"screenX",aCallerType,aError);}int32_tnsGlobalWindow::GetScreenYOuter(CallerTypeaCallerType,ErrorResult&aError){MOZ_RELEASE_ASSERT(IsOuterWindow());returnGetScreenXY(aCallerType,aError).y;}int32_tnsGlobalWindow::GetScreenY(CallerTypeaCallerType,ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(GetScreenYOuter,(aCallerType,aError),aError,0);}voidnsGlobalWindow::GetScreenY(JSContext*aCx,JS::MutableHandle<JS::Value>aValue,CallerTypeaCallerType,ErrorResult&aError){GetReplaceableWindowCoord(aCx,&nsGlobalWindow::GetScreenY,aValue,aCallerType,aError);}voidnsGlobalWindow::SetScreenYOuter(int32_taScreenY,CallerTypeaCallerType,ErrorResult&aError){MOZ_RELEASE_ASSERT(IsOuterWindow());nsCOMPtr<nsIBaseWindow>treeOwnerAsWin=GetTreeOwnerWindow();if(!treeOwnerAsWin){aError.Throw(NS_ERROR_FAILURE);return;}int32_tx,y;aError=treeOwnerAsWin->GetPosition(&x,&y);if(aError.Failed()){return;}CheckSecurityLeftAndTop(nullptr,&aScreenY,aCallerType);y=CSSToDevIntPixels(aScreenY);aError=treeOwnerAsWin->SetPosition(x,y);CheckForDPIChange();}voidnsGlobalWindow::SetScreenY(int32_taScreenY,CallerTypeaCallerType,ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(SetScreenYOuter,(aScreenY,aCallerType,aError),aError,);}voidnsGlobalWindow::SetScreenY(JSContext*aCx,JS::Handle<JS::Value>aValue,CallerTypeaCallerType,ErrorResult&aError){SetReplaceableWindowCoord(aCx,&nsGlobalWindow::SetScreenY,aValue,"screenY",aCallerType,aError);}// NOTE: Arguments to this function should have values scaled to// CSS pixels, not device pixels.voidnsGlobalWindow::CheckSecurityWidthAndHeight(int32_t*aWidth,int32_t*aHeight,CallerTypeaCallerType){MOZ_ASSERT(IsOuterWindow());#ifdef MOZ_XULif(aCallerType!=CallerType::System){// if attempting to resize the window, hide any open popupsnsContentUtils::HidePopupsInDocument(mDoc);}#endif// This one is easy. Just ensure the variable is greater than 100;if((aWidth&&*aWidth<100)||(aHeight&&*aHeight<100)){// Check security state for use in determing window dimensionsif(aCallerType!=CallerType::System){//sec check failedif(aWidth&&*aWidth<100){*aWidth=100;}if(aHeight&&*aHeight<100){*aHeight=100;}}}}// NOTE: Arguments to this function should have values in device pixelsnsresultnsGlobalWindow::SetDocShellWidthAndHeight(int32_taInnerWidth,int32_taInnerHeight){MOZ_ASSERT(IsOuterWindow());NS_ENSURE_TRUE(mDocShell,NS_ERROR_FAILURE);nsCOMPtr<nsIDocShellTreeOwner>treeOwner;mDocShell->GetTreeOwner(getter_AddRefs(treeOwner));NS_ENSURE_TRUE(treeOwner,NS_ERROR_FAILURE);NS_ENSURE_SUCCESS(treeOwner->SizeShellTo(mDocShell,aInnerWidth,aInnerHeight),NS_ERROR_FAILURE);returnNS_OK;}// NOTE: Arguments to this function should have values in app unitsvoidnsGlobalWindow::SetCSSViewportWidthAndHeight(nscoordaInnerWidth,nscoordaInnerHeight){MOZ_ASSERT(IsOuterWindow());RefPtr<nsPresContext>presContext;mDocShell->GetPresContext(getter_AddRefs(presContext));nsRectshellArea=presContext->GetVisibleArea();shellArea.height=aInnerHeight;shellArea.width=aInnerWidth;presContext->SetVisibleArea(shellArea);}// NOTE: Arguments to this function should have values scaled to// CSS pixels, not device pixels.voidnsGlobalWindow::CheckSecurityLeftAndTop(int32_t*aLeft,int32_t*aTop,CallerTypeaCallerType){MOZ_ASSERT(IsOuterWindow());// This one is harder. We have to get the screen size and window dimensions.// Check security state for use in determing window dimensionsif(aCallerType!=CallerType::System){#ifdef MOZ_XUL// if attempting to move the window, hide any open popupsnsContentUtils::HidePopupsInDocument(mDoc);#endifif(nsGlobalWindow*rootWindow=nsGlobalWindow::Cast(GetPrivateRoot())){rootWindow->FlushPendingNotifications(FlushType::Layout);}nsCOMPtr<nsIBaseWindow>treeOwner=GetTreeOwnerWindow();nsCOMPtr<nsIDOMScreen>screen=GetScreen();if(treeOwner&&screen){int32_tscreenLeft,screenTop,screenWidth,screenHeight;int32_twinLeft,winTop,winWidth,winHeight;// Get the window sizetreeOwner->GetPositionAndSize(&winLeft,&winTop,&winWidth,&winHeight);// convert those values to CSS pixels// XXX four separate retrievals of the prescontextwinLeft=DevToCSSIntPixels(winLeft);winTop=DevToCSSIntPixels(winTop);winWidth=DevToCSSIntPixels(winWidth);winHeight=DevToCSSIntPixels(winHeight);// Get the screen dimensions// XXX This should use nsIScreenManager once it's fully fleshed out.screen->GetAvailLeft(&screenLeft);screen->GetAvailWidth(&screenWidth);screen->GetAvailHeight(&screenHeight);#if defined(XP_MACOSX)/* The mac's coordinate system is different from the assumed Windows' system. It offsets by the height of the menubar so that a window placed at (0,0) will be entirely visible. Unfortunately that correction is made elsewhere (in Widget) and the meaning of the Avail... coordinates is overloaded. Here we allow a window to be placed at (0,0) because it does make sense to do so. */screen->GetTop(&screenTop);#elsescreen->GetAvailTop(&screenTop);#endifif(aLeft){if(screenLeft+screenWidth<*aLeft+winWidth)*aLeft=screenLeft+screenWidth-winWidth;if(screenLeft>*aLeft)*aLeft=screenLeft;}if(aTop){if(screenTop+screenHeight<*aTop+winHeight)*aTop=screenTop+screenHeight-winHeight;if(screenTop>*aTop)*aTop=screenTop;}}else{if(aLeft)*aLeft=0;if(aTop)*aTop=0;}}}int32_tnsGlobalWindow::GetScrollBoundaryOuter(SideaSide){MOZ_RELEASE_ASSERT(IsOuterWindow());FlushPendingNotifications(FlushType::Layout);if(nsIScrollableFrame*sf=GetScrollFrame()){returnnsPresContext::AppUnitsToIntCSSPixels(sf->GetScrollRange().Edge(aSide));}return0;}int32_tnsGlobalWindow::GetScrollMinX(ErrorResult&aError){MOZ_ASSERT(IsInnerWindow());FORWARD_TO_OUTER_OR_THROW(GetScrollBoundaryOuter,(eSideLeft),aError,0);}int32_tnsGlobalWindow::GetScrollMinY(ErrorResult&aError){MOZ_ASSERT(IsInnerWindow());FORWARD_TO_OUTER_OR_THROW(GetScrollBoundaryOuter,(eSideTop),aError,0);}int32_tnsGlobalWindow::GetScrollMaxX(ErrorResult&aError){MOZ_ASSERT(IsInnerWindow());FORWARD_TO_OUTER_OR_THROW(GetScrollBoundaryOuter,(eSideRight),aError,0);}int32_tnsGlobalWindow::GetScrollMaxY(ErrorResult&aError){MOZ_ASSERT(IsInnerWindow());FORWARD_TO_OUTER_OR_THROW(GetScrollBoundaryOuter,(eSideBottom),aError,0);}CSSPointnsGlobalWindow::GetScrollXY(boolaDoFlush){MOZ_ASSERT(IsOuterWindow());if(aDoFlush){FlushPendingNotifications(FlushType::Layout);}else{EnsureSizeAndPositionUpToDate();}nsIScrollableFrame*sf=GetScrollFrame();if(!sf){returnCSSIntPoint(0,0);}nsPointscrollPos=sf->GetScrollPosition();if(scrollPos!=nsPoint(0,0)&&!aDoFlush){// Oh, well. This is the expensive case -- the window is scrolled and we// didn't actually flush yet. Repeat, but with a flush, since the content// may get shorter and hence our scroll position may decrease.returnGetScrollXY(true);}returnCSSPoint::FromAppUnits(scrollPos);}doublensGlobalWindow::GetScrollXOuter(){MOZ_RELEASE_ASSERT(IsOuterWindow());returnGetScrollXY(false).x;}doublensGlobalWindow::GetScrollX(ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(GetScrollXOuter,(),aError,0);}doublensGlobalWindow::GetScrollYOuter(){MOZ_RELEASE_ASSERT(IsOuterWindow());returnGetScrollXY(false).y;}doublensGlobalWindow::GetScrollY(ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(GetScrollYOuter,(),aError,0);}uint32_tnsGlobalWindow::Length(){FORWARD_TO_OUTER(Length,(),0);nsDOMWindowList*windows=GetWindowList();returnwindows?windows->GetLength():0;}already_AddRefed<nsPIDOMWindowOuter>nsGlobalWindow::GetTopOuter(){MOZ_ASSERT(IsOuterWindow());nsCOMPtr<nsPIDOMWindowOuter>top=GetScriptableTop();returntop.forget();}already_AddRefed<nsPIDOMWindowOuter>nsGlobalWindow::GetTop(mozilla::ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(GetTopOuter,(),aError,nullptr);}nsPIDOMWindowOuter*nsGlobalWindow::GetChildWindow(constnsAString&aName){nsCOMPtr<nsIDocShell>docShell(GetDocShell());NS_ENSURE_TRUE(docShell,nullptr);nsCOMPtr<nsIDocShellTreeItem>child;docShell->FindChildWithName(aName,false,true,nullptr,nullptr,getter_AddRefs(child));returnchild?child->GetWindow():nullptr;}boolnsGlobalWindow::DispatchCustomEvent(constnsAString&aEventName){MOZ_ASSERT(IsOuterWindow());booldefaultActionEnabled=true;nsContentUtils::DispatchTrustedEvent(mDoc,ToSupports(this),aEventName,true,true,&defaultActionEnabled);returndefaultActionEnabled;}boolnsGlobalWindow::DispatchResizeEvent(constCSSIntSize&aSize){MOZ_ASSERT(IsOuterWindow());ErrorResultres;RefPtr<Event>domEvent=mDoc->CreateEvent(NS_LITERAL_STRING("CustomEvent"),CallerType::System,res);if(res.Failed()){returnfalse;}// We don't init the AutoJSAPI with ourselves because we don't want it// reporting errors to our onerror handlers.AutoJSAPIjsapi;jsapi.Init();JSContext*cx=jsapi.cx();JSAutoCompartmentac(cx,GetWrapperPreserveColor());DOMWindowResizeEventDetaildetail;detail.mWidth=aSize.width;detail.mHeight=aSize.height;JS::Rooted<JS::Value>detailValue(cx);if(!ToJSValue(cx,detail,&detailValue)){returnfalse;}CustomEvent*customEvent=static_cast<CustomEvent*>(domEvent.get());customEvent->InitCustomEvent(cx,NS_LITERAL_STRING("DOMWindowResize"),/* aCanBubble = */true,/* aCancelable = */true,detailValue,res);if(res.Failed()){returnfalse;}domEvent->SetTrusted(true);domEvent->WidgetEventPtr()->mFlags.mOnlyChromeDispatch=true;nsCOMPtr<EventTarget>target=do_QueryInterface(GetOuterWindow());domEvent->SetTarget(target);booldefaultActionEnabled=true;target->DispatchEvent(domEvent,&defaultActionEnabled);returndefaultActionEnabled;}voidnsGlobalWindow::RefreshCompartmentPrincipal(){MOZ_ASSERT(IsInnerWindow());JS_SetCompartmentPrincipals(js::GetObjectCompartment(GetWrapperPreserveColor()),nsJSPrincipals::get(mDoc->NodePrincipal()));}staticalready_AddRefed<nsIDocShellTreeItem>GetCallerDocShellTreeItem(){nsCOMPtr<nsIWebNavigation>callerWebNav=do_GetInterface(GetEntryGlobal());nsCOMPtr<nsIDocShellTreeItem>callerItem=do_QueryInterface(callerWebNav);returncallerItem.forget();}boolnsGlobalWindow::WindowExists(constnsAString&aName,boolaForceNoOpener,boolaLookForCallerOnJSStack){NS_PRECONDITION(IsOuterWindow(),"Must be outer window");NS_PRECONDITION(mDocShell,"Must have docshell");if(aForceNoOpener){returnaName.LowerCaseEqualsLiteral("_self")||aName.LowerCaseEqualsLiteral("_top")||aName.LowerCaseEqualsLiteral("_parent");}nsCOMPtr<nsIDocShellTreeItem>caller;if(aLookForCallerOnJSStack){caller=GetCallerDocShellTreeItem();}if(!caller){caller=mDocShell;}nsCOMPtr<nsIDocShellTreeItem>namedItem;mDocShell->FindItemWithName(aName,nullptr,caller,/* aSkipTabGroup = */false,getter_AddRefs(namedItem));returnnamedItem!=nullptr;}already_AddRefed<nsIWidget>nsGlobalWindow::GetMainWidget(){FORWARD_TO_OUTER(GetMainWidget,(),nullptr);nsCOMPtr<nsIBaseWindow>treeOwnerAsWin=GetTreeOwnerWindow();nsCOMPtr<nsIWidget>widget;if(treeOwnerAsWin){treeOwnerAsWin->GetMainWidget(getter_AddRefs(widget));}returnwidget.forget();}nsIWidget*nsGlobalWindow::GetNearestWidget()const{nsIDocShell*docShell=GetDocShell();NS_ENSURE_TRUE(docShell,nullptr);nsCOMPtr<nsIPresShell>presShell=docShell->GetPresShell();NS_ENSURE_TRUE(presShell,nullptr);nsIFrame*rootFrame=presShell->GetRootFrame();NS_ENSURE_TRUE(rootFrame,nullptr);returnrootFrame->GetView()->GetNearestWidget(nullptr);}voidnsGlobalWindow::SetFullScreenOuter(boolaFullScreen,mozilla::ErrorResult&aError){MOZ_RELEASE_ASSERT(IsOuterWindow());aError=SetFullscreenInternal(FullscreenReason::ForFullscreenMode,aFullScreen);}voidnsGlobalWindow::SetFullScreen(boolaFullScreen,mozilla::ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(SetFullScreenOuter,(aFullScreen,aError),aError,/* void */);}nsresultnsGlobalWindow::SetFullScreen(boolaFullScreen){FORWARD_TO_OUTER(SetFullScreen,(aFullScreen),NS_ERROR_NOT_INITIALIZED);returnSetFullscreenInternal(FullscreenReason::ForFullscreenMode,aFullScreen);}staticvoidFinishDOMFullscreenChange(nsIDocument*aDoc,boolaInDOMFullscreen){if(aInDOMFullscreen){// Ask the document to handle any pending DOM fullscreen change.if(!nsIDocument::HandlePendingFullscreenRequests(aDoc)){// If we don't end up having anything in fullscreen,// async request exiting fullscreen.nsIDocument::AsyncExitFullscreen(aDoc);}}else{// If the window is leaving fullscreen state, also ask the document// to exit from DOM Fullscreen.nsIDocument::ExitFullscreenInDocTree(aDoc);}}structFullscreenTransitionDuration{// The unit of the durations is milliseconduint16_tmFadeIn=0;uint16_tmFadeOut=0;boolIsSuppressed()const{returnmFadeIn==0&&mFadeOut==0;}};staticvoidGetFullscreenTransitionDuration(boolaEnterFullscreen,FullscreenTransitionDuration*aDuration){constchar*pref=aEnterFullscreen?"full-screen-api.transition-duration.enter":"full-screen-api.transition-duration.leave";nsAdoptingCStringprefValue=Preferences::GetCString(pref);if(!prefValue.IsEmpty()){sscanf(prefValue.get(),"%hu%hu",&aDuration->mFadeIn,&aDuration->mFadeOut);}}classFullscreenTransitionTask:publicRunnable{public:FullscreenTransitionTask(constFullscreenTransitionDuration&aDuration,nsGlobalWindow*aWindow,boolaFullscreen,nsIWidget*aWidget,nsIScreen*aScreen,nsISupports*aTransitionData):mozilla::Runnable("FullscreenTransitionTask"),mWindow(aWindow),mWidget(aWidget),mScreen(aScreen),mTransitionData(aTransitionData),mDuration(aDuration),mStage(eBeforeToggle),mFullscreen(aFullscreen){}NS_IMETHODRun()override;private:~FullscreenTransitionTask()override{}/** * The flow of fullscreen transition: * * parent process | child process * ---------------------------------------------------------------- * * | request/exit fullscreen * <-----| * BeforeToggle stage | * | * ToggleFullscreen stage *1 |-----> * | HandleFullscreenRequests * | * <-----| MozAfterPaint event * AfterToggle stage *2 | * | * End stage | * * Note we also start a timer at *1 so that if we don't get MozAfterPaint * from the child process in time, we continue going to *2. */enumStage{// BeforeToggle stage happens before we enter or leave fullscreen// state. In this stage, the task triggers the pre-toggle fullscreen// transition on the widget.eBeforeToggle,// ToggleFullscreen stage actually executes the fullscreen toggle,// and wait for the next paint on the content to continue.eToggleFullscreen,// AfterToggle stage happens after we toggle the fullscreen state.// In this stage, the task triggers the post-toggle fullscreen// transition on the widget.eAfterToggle,// End stage is triggered after the final transition finishes.eEnd};classObserverfinal:publicnsIObserver{public:NS_DECL_ISUPPORTSNS_DECL_NSIOBSERVERexplicitObserver(FullscreenTransitionTask*aTask):mTask(aTask){}private:~Observer()=default;RefPtr<FullscreenTransitionTask>mTask;};staticconstchar*constkPaintedTopic;RefPtr<nsGlobalWindow>mWindow;nsCOMPtr<nsIWidget>mWidget;nsCOMPtr<nsIScreen>mScreen;nsCOMPtr<nsITimer>mTimer;nsCOMPtr<nsISupports>mTransitionData;TimeStampmFullscreenChangeStartTime;FullscreenTransitionDurationmDuration;StagemStage;boolmFullscreen;};constchar*constFullscreenTransitionTask::kPaintedTopic="fullscreen-painted";NS_IMETHODIMPFullscreenTransitionTask::Run(){Stagestage=mStage;mStage=Stage(mStage+1);if(MOZ_UNLIKELY(mWidget->Destroyed())){// If the widget has been destroyed before we get here, don't try to// do anything more. Just let it go and release ourselves.NS_WARNING("The widget to fullscreen has been destroyed");returnNS_OK;}if(stage==eBeforeToggle){profiler_add_marker("Fullscreen transition start");mWidget->PerformFullscreenTransition(nsIWidget::eBeforeFullscreenToggle,mDuration.mFadeIn,mTransitionData,this);}elseif(stage==eToggleFullscreen){profiler_add_marker("Fullscreen toggle start");mFullscreenChangeStartTime=TimeStamp::Now();if(MOZ_UNLIKELY(mWindow->mFullScreen!=mFullscreen)){// This could happen in theory if several fullscreen requests in// different direction happen continuously in a short time. We// need to ensure the fullscreen state matches our target here,// otherwise the widget would change the window state as if we// toggle for Fullscreen Mode instead of Fullscreen API.NS_WARNING("The fullscreen state of the window does not match");mWindow->mFullScreen=mFullscreen;}// Toggle the fullscreen state on the widgetif(!mWindow->SetWidgetFullscreen(FullscreenReason::ForFullscreenAPI,mFullscreen,mWidget,mScreen)){// Fail to setup the widget, call FinishFullscreenChange to// complete fullscreen change directly.mWindow->FinishFullscreenChange(mFullscreen);}// Set observer for the next content paint.nsCOMPtr<nsIObserver>observer=newObserver(this);nsCOMPtr<nsIObserverService>obs=mozilla::services::GetObserverService();obs->AddObserver(observer,kPaintedTopic,false);// There are several edge cases where we may never get the paint// notification, including:// 1. the window/tab is closed before the next paint;// 2. the user has switched to another tab before we get here.// Completely fixing those cases seems to be tricky, and since they// should rarely happen, it probably isn't worth to fix. Hence we// simply add a timeout here to ensure we never hang forever.// In addition, if the page is complicated or the machine is less// powerful, layout could take a long time, in which case, staying// in black screen for that long could hurt user experience even// more than exposing an intermediate state.mTimer=do_CreateInstance(NS_TIMER_CONTRACTID);uint32_ttimeout=Preferences::GetUint("full-screen-api.transition.timeout",1000);mTimer->Init(observer,timeout,nsITimer::TYPE_ONE_SHOT);}elseif(stage==eAfterToggle){Telemetry::AccumulateTimeDelta(Telemetry::FULLSCREEN_TRANSITION_BLACK_MS,mFullscreenChangeStartTime);mWidget->PerformFullscreenTransition(nsIWidget::eAfterFullscreenToggle,mDuration.mFadeOut,mTransitionData,this);}elseif(stage==eEnd){profiler_add_marker("Fullscreen transition end");}returnNS_OK;}NS_IMPL_ISUPPORTS(FullscreenTransitionTask::Observer,nsIObserver)NS_IMETHODIMPFullscreenTransitionTask::Observer::Observe(nsISupports*aSubject,constchar*aTopic,constchar16_t*aData){boolshouldContinue=false;if(strcmp(aTopic,FullscreenTransitionTask::kPaintedTopic)==0){nsCOMPtr<nsPIDOMWindowInner>win(do_QueryInterface(aSubject));nsCOMPtr<nsIWidget>widget=win?nsGlobalWindow::Cast(win)->GetMainWidget():nullptr;if(widget==mTask->mWidget){// The paint notification arrives first. Cancel the timer.mTask->mTimer->Cancel();shouldContinue=true;profiler_add_marker("Fullscreen toggle end");}}else{#ifdef DEBUGMOZ_ASSERT(strcmp(aTopic,NS_TIMER_CALLBACK_TOPIC)==0,"Should only get fullscreen-painted or timer-callback");nsCOMPtr<nsITimer>timer(do_QueryInterface(aSubject));MOZ_ASSERT(timer&&timer==mTask->mTimer,"Should only trigger this with the timer the task created");#endifshouldContinue=true;profiler_add_marker("Fullscreen toggle timeout");}if(shouldContinue){nsCOMPtr<nsIObserverService>obs=mozilla::services::GetObserverService();obs->RemoveObserver(this,kPaintedTopic);mTask->mTimer=nullptr;mTask->Run();}returnNS_OK;}staticboolMakeWidgetFullscreen(nsGlobalWindow*aWindow,FullscreenReasonaReason,boolaFullscreen){nsCOMPtr<nsIWidget>widget=aWindow->GetMainWidget();if(!widget){returnfalse;}FullscreenTransitionDurationduration;boolperformTransition=false;nsCOMPtr<nsISupports>transitionData;if(aReason==FullscreenReason::ForFullscreenAPI){GetFullscreenTransitionDuration(aFullscreen,&duration);if(!duration.IsSuppressed()){performTransition=widget->PrepareForFullscreenTransition(getter_AddRefs(transitionData));}}// We pass nullptr as the screen to SetWidgetFullscreen// and FullscreenTransitionTask, as we do not wish to override// the default screen selection behavior. The screen containing// most of the widget will be selected.if(!performTransition){returnaWindow->SetWidgetFullscreen(aReason,aFullscreen,widget,nullptr);}nsCOMPtr<nsIRunnable>task=newFullscreenTransitionTask(duration,aWindow,aFullscreen,widget,nullptr,transitionData);task->Run();returntrue;}nsresultnsGlobalWindow::SetFullscreenInternal(FullscreenReasonaReason,boolaFullScreen){MOZ_ASSERT(IsOuterWindow());MOZ_ASSERT(nsContentUtils::IsSafeToRunScript(),"Requires safe to run script as it ""may call FinishDOMFullscreenChange");NS_ENSURE_TRUE(mDocShell,NS_ERROR_FAILURE);MOZ_ASSERT(aReason!=FullscreenReason::ForForceExitFullscreen||!aFullScreen,"FullscreenReason::ForForceExitFullscreen can ""only be used with exiting fullscreen");// Only chrome can change our fullscreen mode. Otherwise, the state// can only be changed for DOM fullscreen.if(aReason==FullscreenReason::ForFullscreenMode&&!nsContentUtils::LegacyIsCallerChromeOrNativeCode()){returnNS_OK;}// SetFullScreen needs to be called on the root window, so get that// via the DocShell tree, and if we are not already the root,// call SetFullScreen on that window instead.nsCOMPtr<nsIDocShellTreeItem>rootItem;mDocShell->GetRootTreeItem(getter_AddRefs(rootItem));nsCOMPtr<nsPIDOMWindowOuter>window=rootItem?rootItem->GetWindow():nullptr;if(!window)returnNS_ERROR_FAILURE;if(rootItem!=mDocShell)returnwindow->SetFullscreenInternal(aReason,aFullScreen);// make sure we don't try to set full screen on a non-chrome window,// which might happen in embedding worldif(mDocShell->ItemType()!=nsIDocShellTreeItem::typeChrome)returnNS_ERROR_FAILURE;// If we are already in full screen mode, just return.if(mFullScreen==aFullScreen)returnNS_OK;// Note that although entering DOM fullscreen could also cause// consequential calls to this method, those calls will be skipped// at the condition above.if(aReason==FullscreenReason::ForFullscreenMode){if(!aFullScreen&&!mFullscreenMode){// If we are exiting fullscreen mode, but we actually didn't// entered fullscreen mode, the fullscreen state was only for// the Fullscreen API. Change the reason here so that we can// perform transition for it.aReason=FullscreenReason::ForFullscreenAPI;}else{mFullscreenMode=aFullScreen;}}else{// If we are exiting from DOM fullscreen while we initially make// the window fullscreen because of fullscreen mode, don't restore// the window. But we still need to exit the DOM fullscreen state.if(!aFullScreen&&mFullscreenMode){FinishDOMFullscreenChange(mDoc,false);returnNS_OK;}}// Prevent chrome documents which are still loading from resizing// the window after we set fullscreen mode.nsCOMPtr<nsIBaseWindow>treeOwnerAsWin=GetTreeOwnerWindow();nsCOMPtr<nsIXULWindow>xulWin(do_GetInterface(treeOwnerAsWin));if(aFullScreen&&xulWin){xulWin->SetIntrinsicallySized(false);}// Set this before so if widget sends an event indicating its// gone full screen, the state trap above works.mFullScreen=aFullScreen;// Sometimes we don't want the top-level widget to actually go fullscreen,// for example in the B2G desktop client, we don't want the emulated screen// dimensions to appear to increase when entering fullscreen mode; we just// want the content to fill the entire client area of the emulator window.if(!Preferences::GetBool("full-screen-api.ignore-widgets",false)){if(MakeWidgetFullscreen(this,aReason,aFullScreen)){// The rest of code for switching fullscreen is in nsGlobalWindow::// FinishFullscreenChange() which will be called after sizemodechange// event is dispatched.returnNS_OK;}}FinishFullscreenChange(aFullScreen);returnNS_OK;}boolnsGlobalWindow::SetWidgetFullscreen(FullscreenReasonaReason,boolaIsFullscreen,nsIWidget*aWidget,nsIScreen*aScreen){MOZ_ASSERT(IsOuterWindow());MOZ_ASSERT(this==GetTopInternal(),"Only topmost window should call this");MOZ_ASSERT(!AsOuter()->GetFrameElementInternal(),"Content window should not call this");MOZ_ASSERT(XRE_GetProcessType()==GeckoProcessType_Default);if(!NS_WARN_IF(!IsChromeWindow())){autochromeWin=static_cast<nsGlobalChromeWindow*>(this);if(!NS_WARN_IF(chromeWin->mFullscreenPresShell)){if(nsIPresShell*shell=mDocShell->GetPresShell()){if(nsRefreshDriver*rd=shell->GetRefreshDriver()){chromeWin->mFullscreenPresShell=do_GetWeakReference(shell);MOZ_ASSERT(chromeWin->mFullscreenPresShell);rd->SetIsResizeSuppressed();rd->Freeze();}}}}nsresultrv=aReason==FullscreenReason::ForFullscreenMode?// If we enter fullscreen for fullscreen mode, we want// the native system behavior.aWidget->MakeFullScreenWithNativeTransition(aIsFullscreen,aScreen):aWidget->MakeFullScreen(aIsFullscreen,aScreen);returnNS_SUCCEEDED(rv);}/* virtual */voidnsGlobalWindow::FinishFullscreenChange(boolaIsFullscreen){MOZ_ASSERT(IsOuterWindow());if(aIsFullscreen!=mFullScreen){NS_WARNING("Failed to toggle fullscreen state of the widget");// We failed to make the widget enter fullscreen.// Stop further changes and restore the state.if(!aIsFullscreen){mFullScreen=false;mFullscreenMode=false;}else{MOZ_ASSERT_UNREACHABLE("Failed to exit fullscreen?");mFullScreen=true;// We don't know how code can reach here. Not sure// what value should be set for fullscreen mode.mFullscreenMode=false;}return;}// Note that we must call this to toggle the DOM fullscreen state// of the document before dispatching the "fullscreen" event, so// that the chrome can distinguish between browser fullscreen mode// and DOM fullscreen.FinishDOMFullscreenChange(mDoc,mFullScreen);// dispatch a "fullscreen" DOM event so that XUL apps can// respond visually if we are kicked into full screen modeDispatchCustomEvent(NS_LITERAL_STRING("fullscreen"));if(!NS_WARN_IF(!IsChromeWindow())){autochromeWin=static_cast<nsGlobalChromeWindow*>(this);if(nsCOMPtr<nsIPresShell>shell=do_QueryReferent(chromeWin->mFullscreenPresShell)){if(nsRefreshDriver*rd=shell->GetRefreshDriver()){rd->Thaw();}chromeWin->mFullscreenPresShell=nullptr;}}if(!mWakeLock&&mFullScreen){RefPtr<power::PowerManagerService>pmService=power::PowerManagerService::GetInstance();if(!pmService){return;}// XXXkhuey using the inner here, do we need to do something if it changes?ErrorResultrv;mWakeLock=pmService->NewWakeLock(NS_LITERAL_STRING("DOM_Fullscreen"),AsOuter()->GetCurrentInnerWindow(),rv);NS_WARNING_ASSERTION(!rv.Failed(),"Failed to lock the wakelock");rv.SuppressException();}elseif(mWakeLock&&!mFullScreen){ErrorResultrv;mWakeLock->Unlock(rv);mWakeLock=nullptr;rv.SuppressException();}}boolnsGlobalWindow::FullScreen()const{MOZ_ASSERT(IsOuterWindow());NS_ENSURE_TRUE(mDocShell,mFullScreen);// Get the fullscreen value of the root window, to always have the value// accurate, even when called from content.nsCOMPtr<nsIDocShellTreeItem>rootItem;mDocShell->GetRootTreeItem(getter_AddRefs(rootItem));if(rootItem==mDocShell){if(!XRE_IsContentProcess()){// We are the root window. Return our internal value.returnmFullScreen;}if(nsCOMPtr<nsIWidget>widget=GetNearestWidget()){// We are in content process, figure out the value from// the sizemode of the puppet widget.returnwidget->SizeMode()==nsSizeMode_Fullscreen;}returnfalse;}nsCOMPtr<nsPIDOMWindowOuter>window=rootItem->GetWindow();NS_ENSURE_TRUE(window,mFullScreen);returnnsGlobalWindow::Cast(window)->FullScreen();}boolnsGlobalWindow::GetFullScreenOuter(){MOZ_RELEASE_ASSERT(IsOuterWindow());returnFullScreen();}boolnsGlobalWindow::GetFullScreen(ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(GetFullScreenOuter,(),aError,false);}boolnsGlobalWindow::GetFullScreen(){FORWARD_TO_INNER(GetFullScreen,(),false);ErrorResultdummy;boolfullscreen=GetFullScreen(dummy);dummy.SuppressException();returnfullscreen;}voidnsGlobalWindow::Dump(constnsAString&aStr){if(!nsContentUtils::DOMWindowDumpEnabled()){return;}char*cstr=ToNewUTF8String(aStr);#if defined(XP_MACOSX)// have to convert \r to \n so that printing to the console workschar*c=cstr,*cEnd=cstr+strlen(cstr);while(c<cEnd){if(*c=='\r')*c='\n';c++;}#endifif(cstr){MOZ_LOG(nsContentUtils::DOMDumpLog(),LogLevel::Debug,("[Window.Dump] %s",cstr));#ifdef XP_WINPrintToDebugger(cstr);#endif#ifdef ANDROID__android_log_write(ANDROID_LOG_INFO,"GeckoDump",cstr);#endifFILE*fp=gDumpFile?gDumpFile:stdout;fputs(cstr,fp);fflush(fp);free(cstr);}}voidnsGlobalWindow::EnsureReflowFlushAndPaint(){MOZ_ASSERT(IsOuterWindow());NS_ASSERTION(mDocShell,"EnsureReflowFlushAndPaint() called with no ""docshell!");if(!mDocShell)return;nsCOMPtr<nsIPresShell>presShell=mDocShell->GetPresShell();if(!presShell)return;// Flush pending reflows.if(mDoc){mDoc->FlushPendingNotifications(FlushType::Layout);}// Unsuppress painting.presShell->UnsuppressPainting();}// staticvoidnsGlobalWindow::MakeScriptDialogTitle(nsAString&aOutTitle,nsIPrincipal*aSubjectPrincipal){MOZ_ASSERT(aSubjectPrincipal);aOutTitle.Truncate();// Try to get a host from the running principal -- this will do the// right thing for javascript: and data: documents.nsCOMPtr<nsIURI>uri;nsresultrv=aSubjectPrincipal->GetURI(getter_AddRefs(uri));// Note - The check for the current JSContext here isn't necessarily sensical.// It's just designed to preserve existing behavior during a mass-conversion// patch.if(NS_SUCCEEDED(rv)&&uri&&nsContentUtils::GetCurrentJSContext()){// remove user:pass for privacy and spoof preventionnsCOMPtr<nsIURIFixup>fixup(do_GetService(NS_URIFIXUP_CONTRACTID));if(fixup){nsCOMPtr<nsIURI>fixedURI;rv=fixup->CreateExposableURI(uri,getter_AddRefs(fixedURI));if(NS_SUCCEEDED(rv)&&fixedURI){nsAutoCStringhost;fixedURI->GetHost(host);if(!host.IsEmpty()){// if this URI has a host we'll show it. For other// schemes (e.g. file:) we fall back to the localized// generic stringnsAutoCStringprepath;fixedURI->GetPrePath(prepath);NS_ConvertUTF8toUTF16ucsPrePath(prepath);constchar16_t*formatStrings[]={ucsPrePath.get()};nsXPIDLStringtempString;nsContentUtils::FormatLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,"ScriptDlgHeading",formatStrings,tempString);aOutTitle=tempString;}}}}if(aOutTitle.IsEmpty()){// We didn't find a host so use the generic headingnsXPIDLStringtempString;nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,"ScriptDlgGenericHeading",tempString);aOutTitle=tempString;}// Just in caseif(aOutTitle.IsEmpty()){NS_WARNING("could not get ScriptDlgGenericHeading string from string bundle");aOutTitle.AssignLiteral("[Script]");}}boolnsGlobalWindow::CanMoveResizeWindows(CallerTypeaCallerType){MOZ_ASSERT(IsOuterWindow());// When called from chrome, we can avoid the following checks.if(aCallerType!=CallerType::System){// Don't allow scripts to move or resize windows that were not opened by a// script.if(!mHadOriginalOpener){returnfalse;}if(!CanSetProperty("dom.disable_window_move_resize")){returnfalse;}// Ignore the request if we have more than one tab in the window.uint32_titemCount=0;if(XRE_IsContentProcess()){nsCOMPtr<nsIDocShell>docShell=GetDocShell();if(docShell){nsCOMPtr<nsITabChild>child=docShell->GetTabChild();if(child){child->SendGetTabCount(&itemCount);}}}else{nsCOMPtr<nsIDocShellTreeOwner>treeOwner=GetTreeOwner();if(!treeOwner||NS_FAILED(treeOwner->GetTabCount(&itemCount))){itemCount=0;}}if(itemCount>1){returnfalse;}}if(mDocShell){boolallow;nsresultrv=mDocShell->GetAllowWindowControl(&allow);if(NS_SUCCEEDED(rv)&&!allow)returnfalse;}if(gMouseDown&&!gDragServiceDisabled){nsCOMPtr<nsIDragService>ds=do_GetService("@mozilla.org/widget/dragservice;1");if(ds){gDragServiceDisabled=true;ds->Suppress();}}returntrue;}boolnsGlobalWindow::AlertOrConfirm(boolaAlert,constnsAString&aMessage,nsIPrincipal&aSubjectPrincipal,ErrorResult&aError){// XXX This method is very similar to nsGlobalWindow::Prompt, make// sure any modifications here don't need to happen over there!MOZ_ASSERT(IsOuterWindow());if(!AreDialogsEnabled()){// Just silently return. In the case of alert(), the return value is// ignored. In the case of confirm(), returning false is the same thing as// would happen if the user cancels.returnfalse;}// Reset popup state while opening a modal dialog, and firing events// about the dialog, to prevent the current state from being active// the whole time a modal dialog is open.nsAutoPopupStatePusherpopupStatePusher(openAbused,true);// Before bringing up the window, unsuppress painting and flush// pending reflows.EnsureReflowFlushAndPaint();nsAutoStringtitle;MakeScriptDialogTitle(title,&aSubjectPrincipal);// Remove non-terminating null characters from the// string. See bug #310037.nsAutoStringfinal;nsContentUtils::StripNullChars(aMessage,final);nsresultrv;nsCOMPtr<nsIPromptFactory>promptFac=do_GetService("@mozilla.org/prompter;1",&rv);if(NS_FAILED(rv)){aError.Throw(rv);returnfalse;}nsCOMPtr<nsIPrompt>prompt;aError=promptFac->GetPrompt(AsOuter(),NS_GET_IID(nsIPrompt),getter_AddRefs(prompt));if(aError.Failed()){returnfalse;}// Always allow tab modal prompts for alert and confirm.if(nsCOMPtr<nsIWritablePropertyBag2>promptBag=do_QueryInterface(prompt)){promptBag->SetPropertyAsBool(NS_LITERAL_STRING("allowTabModal"),true);}boolresult=false;nsAutoSyncOperationsync(mDoc);if(ShouldPromptToBlockDialogs()){booldisallowDialog=false;nsXPIDLStringlabel;nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,"ScriptDialogLabel",label);aError=aAlert?prompt->AlertCheck(title.get(),final.get(),label.get(),&disallowDialog):prompt->ConfirmCheck(title.get(),final.get(),label.get(),&disallowDialog,&result);if(disallowDialog)DisableDialogs();}else{aError=aAlert?prompt->Alert(title.get(),final.get()):prompt->Confirm(title.get(),final.get(),&result);}returnresult;}voidnsGlobalWindow::Alert(nsIPrincipal&aSubjectPrincipal,ErrorResult&aError){MOZ_ASSERT(IsInnerWindow());Alert(EmptyString(),aSubjectPrincipal,aError);}voidnsGlobalWindow::AlertOuter(constnsAString&aMessage,nsIPrincipal&aSubjectPrincipal,ErrorResult&aError){MOZ_RELEASE_ASSERT(IsOuterWindow());AlertOrConfirm(/* aAlert = */true,aMessage,aSubjectPrincipal,aError);}voidnsGlobalWindow::Alert(constnsAString&aMessage,nsIPrincipal&aSubjectPrincipal,ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(AlertOuter,(aMessage,aSubjectPrincipal,aError),aError,);}boolnsGlobalWindow::ConfirmOuter(constnsAString&aMessage,nsIPrincipal&aSubjectPrincipal,ErrorResult&aError){MOZ_RELEASE_ASSERT(IsOuterWindow());returnAlertOrConfirm(/* aAlert = */false,aMessage,aSubjectPrincipal,aError);}boolnsGlobalWindow::Confirm(constnsAString&aMessage,nsIPrincipal&aSubjectPrincipal,ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(ConfirmOuter,(aMessage,aSubjectPrincipal,aError),aError,false);}already_AddRefed<Promise>nsGlobalWindow::Fetch(constRequestOrUSVString&aInput,constRequestInit&aInit,CallerTypeaCallerType,ErrorResult&aRv){returnFetchRequest(this,aInput,aInit,aCallerType,aRv);}voidnsGlobalWindow::PromptOuter(constnsAString&aMessage,constnsAString&aInitial,nsAString&aReturn,nsIPrincipal&aSubjectPrincipal,ErrorResult&aError){// XXX This method is very similar to nsGlobalWindow::AlertOrConfirm, make// sure any modifications here don't need to happen over there!MOZ_RELEASE_ASSERT(IsOuterWindow());SetDOMStringToNull(aReturn);if(!AreDialogsEnabled()){// Return null, as if the user just canceled the prompt.return;}// Reset popup state while opening a modal dialog, and firing events// about the dialog, to prevent the current state from being active// the whole time a modal dialog is open.nsAutoPopupStatePusherpopupStatePusher(openAbused,true);// Before bringing up the window, unsuppress painting and flush// pending reflows.EnsureReflowFlushAndPaint();nsAutoStringtitle;MakeScriptDialogTitle(title,&aSubjectPrincipal);// Remove non-terminating null characters from the// string. See bug #310037.nsAutoStringfixedMessage,fixedInitial;nsContentUtils::StripNullChars(aMessage,fixedMessage);nsContentUtils::StripNullChars(aInitial,fixedInitial);nsresultrv;nsCOMPtr<nsIPromptFactory>promptFac=do_GetService("@mozilla.org/prompter;1",&rv);if(NS_FAILED(rv)){aError.Throw(rv);return;}nsCOMPtr<nsIPrompt>prompt;aError=promptFac->GetPrompt(AsOuter(),NS_GET_IID(nsIPrompt),getter_AddRefs(prompt));if(aError.Failed()){return;}// Always allow tab modal prompts for prompt.if(nsCOMPtr<nsIWritablePropertyBag2>promptBag=do_QueryInterface(prompt)){promptBag->SetPropertyAsBool(NS_LITERAL_STRING("allowTabModal"),true);}// Pass in the default value, if any.char16_t*inoutValue=ToNewUnicode(fixedInitial);booldisallowDialog=false;nsXPIDLStringlabel;if(ShouldPromptToBlockDialogs()){nsContentUtils::GetLocalizedString(nsContentUtils::eCOMMON_DIALOG_PROPERTIES,"ScriptDialogLabel",label);}nsAutoSyncOperationsync(mDoc);boolok;aError=prompt->Prompt(title.get(),fixedMessage.get(),&inoutValue,label.get(),&disallowDialog,&ok);if(disallowDialog){DisableDialogs();}if(aError.Failed()){return;}nsAdoptingStringoutValue(inoutValue);if(ok&&outValue){aReturn.Assign(outValue);}}voidnsGlobalWindow::Prompt(constnsAString&aMessage,constnsAString&aInitial,nsAString&aReturn,nsIPrincipal&aSubjectPrincipal,ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(PromptOuter,(aMessage,aInitial,aReturn,aSubjectPrincipal,aError),aError,);}voidnsGlobalWindow::FocusOuter(ErrorResult&aError){MOZ_RELEASE_ASSERT(IsOuterWindow());nsIFocusManager*fm=nsFocusManager::GetFocusManager();if(!fm){return;}nsCOMPtr<nsIBaseWindow>baseWin=do_QueryInterface(mDocShell);boolisVisible=false;if(baseWin){baseWin->GetVisibility(&isVisible);}if(!isVisible){// A hidden tab is being focused, ignore this call.return;}nsCOMPtr<nsPIDOMWindowInner>caller=do_QueryInterface(GetEntryGlobal());nsPIDOMWindowOuter*callerOuter=caller?caller->GetOuterWindow():nullptr;nsCOMPtr<nsPIDOMWindowOuter>opener=GetOpener();// Enforce dom.disable_window_flip (for non-chrome), but still allow the// window which opened us to raise us at times when popups are allowed// (bugs 355482 and 369306).boolcanFocus=CanSetProperty("dom.disable_window_flip")||(opener==callerOuter&&RevisePopupAbuseLevel(gPopupControlState)<openAbused);nsCOMPtr<mozIDOMWindowProxy>activeDOMWindow;fm->GetActiveWindow(getter_AddRefs(activeDOMWindow));nsCOMPtr<nsIDocShellTreeItem>rootItem;mDocShell->GetRootTreeItem(getter_AddRefs(rootItem));nsCOMPtr<nsPIDOMWindowOuter>rootWin=rootItem?rootItem->GetWindow():nullptr;auto*activeWindow=nsPIDOMWindowOuter::From(activeDOMWindow);boolisActive=(rootWin==activeWindow);nsCOMPtr<nsIBaseWindow>treeOwnerAsWin=GetTreeOwnerWindow();if(treeOwnerAsWin&&(canFocus||isActive)){boolisEnabled=true;if(NS_SUCCEEDED(treeOwnerAsWin->GetEnabled(&isEnabled))&&!isEnabled){NS_WARNING("Should not try to set the focus on a disabled window");return;}// XXXndeakin not sure what this is for or if it should go somewhere elsensCOMPtr<nsIEmbeddingSiteWindow>embeddingWin(do_GetInterface(treeOwnerAsWin));if(embeddingWin)embeddingWin->SetFocus();}if(!mDocShell){return;}nsCOMPtr<nsIPresShell>presShell;// Don't look for a presshell if we're a root chrome window that's got// about:blank loaded. We don't want to focus our widget in that case.// XXXbz should we really be checking for IsInitialDocument() instead?boollookForPresShell=true;if(mDocShell->ItemType()==nsIDocShellTreeItem::typeChrome&&GetPrivateRoot()==AsOuter()&&mDoc){nsIURI*ourURI=mDoc->GetDocumentURI();if(ourURI){lookForPresShell=!NS_IsAboutBlank(ourURI);}}if(lookForPresShell){mDocShell->GetEldestPresShell(getter_AddRefs(presShell));}nsCOMPtr<nsIDocShellTreeItem>parentDsti;mDocShell->GetParent(getter_AddRefs(parentDsti));// set the parent's current focus to the frame containing this window.nsCOMPtr<nsPIDOMWindowOuter>parent=parentDsti?parentDsti->GetWindow():nullptr;if(parent){nsCOMPtr<nsIDocument>parentdoc=parent->GetDoc();if(!parentdoc){return;}nsIContent*frame=parentdoc->FindContentForSubDocument(mDoc);nsCOMPtr<nsIDOMElement>frameElement=do_QueryInterface(frame);if(frameElement){uint32_tflags=nsIFocusManager::FLAG_NOSCROLL;if(canFocus)flags|=nsIFocusManager::FLAG_RAISE;aError=fm->SetFocus(frameElement,flags);}return;}if(canFocus){// if there is no parent, this must be a toplevel window, so raise the// window if canFocus is true. If this is a child process, the raise// window request will get forwarded to the parent by the puppet widget.aError=fm->SetActiveWindow(AsOuter());}}voidnsGlobalWindow::Focus(ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(FocusOuter,(aError),aError,);}nsresultnsGlobalWindow::Focus(){FORWARD_TO_INNER(Focus,(),NS_ERROR_UNEXPECTED);ErrorResultrv;Focus(rv);returnrv.StealNSResult();}voidnsGlobalWindow::BlurOuter(){MOZ_RELEASE_ASSERT(IsOuterWindow());// If dom.disable_window_flip == true, then content should not be allowed// to call this function (this would allow popunders, bug 369306)if(!CanSetProperty("dom.disable_window_flip")){return;}// If embedding apps don't implement nsIEmbeddingSiteWindow, we// shouldn't throw exceptions to web content.nsCOMPtr<nsIDocShellTreeOwner>treeOwner=GetTreeOwner();nsCOMPtr<nsIEmbeddingSiteWindow>siteWindow(do_GetInterface(treeOwner));if(siteWindow){// This method call may cause mDocShell to become nullptr.siteWindow->Blur();// if the root is focused, clear the focusnsIFocusManager*fm=nsFocusManager::GetFocusManager();if(fm&&mDoc){nsCOMPtr<nsIDOMElement>element;fm->GetFocusedElementForWindow(AsOuter(),false,nullptr,getter_AddRefs(element));nsCOMPtr<nsIContent>content=do_QueryInterface(element);if(content==mDoc->GetRootElement()){fm->ClearFocus(AsOuter());}}}}voidnsGlobalWindow::Blur(ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(BlurOuter,(),aError,);}voidnsGlobalWindow::BackOuter(ErrorResult&aError){MOZ_RELEASE_ASSERT(IsOuterWindow());nsCOMPtr<nsIWebNavigation>webNav(do_QueryInterface(mDocShell));if(!webNav){aError.Throw(NS_ERROR_FAILURE);return;}aError=webNav->GoBack();}voidnsGlobalWindow::Back(ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(BackOuter,(aError),aError,);}voidnsGlobalWindow::ForwardOuter(ErrorResult&aError){MOZ_RELEASE_ASSERT(IsOuterWindow());nsCOMPtr<nsIWebNavigation>webNav(do_QueryInterface(mDocShell));if(!webNav){aError.Throw(NS_ERROR_FAILURE);return;}aError=webNav->GoForward();}voidnsGlobalWindow::Forward(ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(ForwardOuter,(aError),aError,);}voidnsGlobalWindow::HomeOuter(nsIPrincipal&aSubjectPrincipal,ErrorResult&aError){MOZ_RELEASE_ASSERT(IsOuterWindow());if(!mDocShell){return;}nsAdoptingStringhomeURL=Preferences::GetLocalizedString(PREF_BROWSER_STARTUP_HOMEPAGE);if(homeURL.IsEmpty()){// if all else fails, use this#ifdef DEBUG_sethprintf("all else failed. using %s as the home page\n",DEFAULT_HOME_PAGE);#endifCopyASCIItoUTF16(DEFAULT_HOME_PAGE,homeURL);}#ifdef MOZ_PHOENIX{// Firefox lets the user specify multiple home pages to open in// individual tabs by separating them with '|'. Since we don't// have the machinery in place to easily open new tabs from here,// simply truncate the homeURL at the first '|' character to// prevent any possibilities of leaking the users list of home// pages to the first home page.//// Once bug https://bugzilla.mozilla.org/show_bug.cgi?id=221445 is// fixed we can revisit this.int32_tfirstPipe=homeURL.FindChar('|');if(firstPipe>0){homeURL.Truncate(firstPipe);}}#endifnsCOMPtr<nsIWebNavigation>webNav(do_QueryInterface(mDocShell));if(!webNav){aError.Throw(NS_ERROR_FAILURE);return;}aError=webNav->LoadURI(homeURL.get(),nsIWebNavigation::LOAD_FLAGS_NONE,nullptr,nullptr,nullptr,&aSubjectPrincipal);}voidnsGlobalWindow::Home(nsIPrincipal&aSubjectPrincipal,ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(HomeOuter,(aSubjectPrincipal,aError),aError,);}voidnsGlobalWindow::StopOuter(ErrorResult&aError){MOZ_RELEASE_ASSERT(IsOuterWindow());nsCOMPtr<nsIWebNavigation>webNav(do_QueryInterface(mDocShell));if(webNav){aError=webNav->Stop(nsIWebNavigation::STOP_ALL);}}voidnsGlobalWindow::Stop(ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(StopOuter,(aError),aError,);}voidnsGlobalWindow::PrintOuter(ErrorResult&aError){MOZ_RELEASE_ASSERT(IsOuterWindow());#ifdef NS_PRINTINGif(Preferences::GetBool("dom.disable_window_print",false)){aError.Throw(NS_ERROR_NOT_AVAILABLE);return;}if(!AreDialogsEnabled()){// We probably want to keep throwing here; silently doing nothing is a bit// weird given the typical use cases of print().aError.Throw(NS_ERROR_NOT_AVAILABLE);return;}if(ShouldPromptToBlockDialogs()&&!ConfirmDialogIfNeeded()){aError.Throw(NS_ERROR_NOT_AVAILABLE);return;}nsCOMPtr<nsIWebBrowserPrint>webBrowserPrint;if(NS_SUCCEEDED(GetInterface(NS_GET_IID(nsIWebBrowserPrint),getter_AddRefs(webBrowserPrint)))){nsAutoSyncOperationsync(GetCurrentInnerWindowInternal()?GetCurrentInnerWindowInternal()->mDoc.get():nullptr);nsCOMPtr<nsIPrintSettingsService>printSettingsService=do_GetService("@mozilla.org/gfx/printsettings-service;1");nsCOMPtr<nsIPrintSettings>printSettings;if(printSettingsService){boolprintSettingsAreGlobal=Preferences::GetBool("print.use_global_printsettings",false);if(printSettingsAreGlobal){printSettingsService->GetGlobalPrintSettings(getter_AddRefs(printSettings));nsXPIDLStringprinterName;printSettings->GetPrinterName(getter_Copies(printerName));boolshouldGetDefaultPrinterName=printerName.IsEmpty();#ifdef MOZ_X11// In Linux, GTK backend does not support per printer settings.// Calling GetDefaultPrinterName causes a sandbox violation (see Bug 1329216).// The printer name is not needed anywhere else on Linux before it gets to the parent.// In the parent, we will then query the default printer name if no name is set.// Unless we are in the parent, we will skip this part.if(!XRE_IsParentProcess()){shouldGetDefaultPrinterName=false;}#endifif(shouldGetDefaultPrinterName){printSettingsService->GetDefaultPrinterName(getter_Copies(printerName));printSettings->SetPrinterName(printerName);}printSettingsService->InitPrintSettingsFromPrinter(printerName,printSettings);printSettingsService->InitPrintSettingsFromPrefs(printSettings,true,nsIPrintSettings::kInitSaveAll);}else{printSettingsService->GetNewPrintSettings(getter_AddRefs(printSettings));}EnterModalState();webBrowserPrint->Print(printSettings,nullptr);LeaveModalState();boolsavePrintSettings=Preferences::GetBool("print.save_print_settings",false);if(printSettingsAreGlobal&&savePrintSettings){printSettingsService->SavePrintSettingsToPrefs(printSettings,true,nsIPrintSettings::kInitSaveAll);printSettingsService->SavePrintSettingsToPrefs(printSettings,false,nsIPrintSettings::kInitSavePrinterName);}}else{webBrowserPrint->GetGlobalPrintSettings(getter_AddRefs(printSettings));webBrowserPrint->Print(printSettings,nullptr);}}#endif //NS_PRINTING}voidnsGlobalWindow::Print(ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(PrintOuter,(aError),aError,);}voidnsGlobalWindow::MoveToOuter(int32_taXPos,int32_taYPos,CallerTypeaCallerType,ErrorResult&aError){MOZ_RELEASE_ASSERT(IsOuterWindow());/* * If caller is not chrome and the user has not explicitly exempted the site, * prevent window.moveTo() by exiting early */if(!CanMoveResizeWindows(aCallerType)||IsFrame()){return;}nsCOMPtr<nsIBaseWindow>treeOwnerAsWin=GetTreeOwnerWindow();if(!treeOwnerAsWin){aError.Throw(NS_ERROR_FAILURE);return;}nsCOMPtr<nsIScreenManager>screenMgr=do_GetService("@mozilla.org/gfx/screenmanager;1");nsCOMPtr<nsIScreen>screen;if(screenMgr){CSSIntSizesize;GetInnerSize(size);screenMgr->ScreenForRect(aXPos,aYPos,size.width,size.height,getter_AddRefs(screen));}if(screen){// On secondary displays, the "CSS px" coordinates are offset so that they// share their origin with global desktop pixels, to avoid ambiguities in// the coordinate space when there are displays with different DPIs.// (See the corresponding code in GetScreenXY() above.)int32_tscreenLeftDeskPx,screenTopDeskPx,w,h;screen->GetRectDisplayPix(&screenLeftDeskPx,&screenTopDeskPx,&w,&h);CSSIntPointcssPos(aXPos-screenLeftDeskPx,aYPos-screenTopDeskPx);CheckSecurityLeftAndTop(&cssPos.x,&cssPos.y,aCallerType);doublescale;screen->GetDefaultCSSScaleFactor(&scale);LayoutDevicePointdevPos=cssPos*CSSToLayoutDeviceScale(scale);screen->GetContentsScaleFactor(&scale);DesktopPointdeskPos=devPos/DesktopToLayoutDeviceScale(scale);aError=treeOwnerAsWin->SetPositionDesktopPix(screenLeftDeskPx+deskPos.x,screenTopDeskPx+deskPos.y);}else{// We couldn't find a screen? Just assume a 1:1 mapping.CSSIntPointcssPos(aXPos,aXPos);CheckSecurityLeftAndTop(&cssPos.x,&cssPos.y,aCallerType);LayoutDevicePointdevPos=cssPos*CSSToLayoutDeviceScale(1.0);aError=treeOwnerAsWin->SetPosition(devPos.x,devPos.y);}CheckForDPIChange();}voidnsGlobalWindow::MoveTo(int32_taXPos,int32_taYPos,CallerTypeaCallerType,ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(MoveToOuter,(aXPos,aYPos,aCallerType,aError),aError,);}voidnsGlobalWindow::MoveByOuter(int32_taXDif,int32_taYDif,CallerTypeaCallerType,ErrorResult&aError){MOZ_RELEASE_ASSERT(IsOuterWindow());/* * If caller is not chrome and the user has not explicitly exempted the site, * prevent window.moveBy() by exiting early */if(!CanMoveResizeWindows(aCallerType)||IsFrame()){return;}nsCOMPtr<nsIBaseWindow>treeOwnerAsWin=GetTreeOwnerWindow();if(!treeOwnerAsWin){aError.Throw(NS_ERROR_FAILURE);return;}// To do this correctly we have to convert what we get from GetPosition// into CSS pixels, add the arguments, do the security check, and// then convert back to device pixels for the call to SetPosition.int32_tx,y;aError=treeOwnerAsWin->GetPosition(&x,&y);if(aError.Failed()){return;}// mild abuse of a "size" object so we don't need more helper functionsnsIntSizecssPos(DevToCSSIntPixels(nsIntSize(x,y)));cssPos.width+=aXDif;cssPos.height+=aYDif;CheckSecurityLeftAndTop(&cssPos.width,&cssPos.height,aCallerType);nsIntSizenewDevPos(CSSToDevIntPixels(cssPos));aError=treeOwnerAsWin->SetPosition(newDevPos.width,newDevPos.height);CheckForDPIChange();}voidnsGlobalWindow::MoveBy(int32_taXDif,int32_taYDif,CallerTypeaCallerType,ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(MoveByOuter,(aXDif,aYDif,aCallerType,aError),aError,);}nsresultnsGlobalWindow::MoveBy(int32_taXDif,int32_taYDif){FORWARD_TO_OUTER(MoveBy,(aXDif,aYDif),NS_ERROR_UNEXPECTED);ErrorResultrv;MoveByOuter(aXDif,aYDif,CallerType::System,rv);returnrv.StealNSResult();}voidnsGlobalWindow::ResizeToOuter(int32_taWidth,int32_taHeight,CallerTypeaCallerType,ErrorResult&aError){MOZ_RELEASE_ASSERT(IsOuterWindow());/* * If caller is a browser-element then dispatch a resize event to * the embedder. */if(mDocShell&&mDocShell->GetIsMozBrowser()){CSSIntSizesize(aWidth,aHeight);if(!DispatchResizeEvent(size)){// The embedder chose to prevent the default action for this// event, so let's not resize this window after all...return;}}/* * If caller is not chrome and the user has not explicitly exempted the site, * prevent window.resizeTo() by exiting early */if(!CanMoveResizeWindows(aCallerType)||IsFrame()){return;}nsCOMPtr<nsIBaseWindow>treeOwnerAsWin=GetTreeOwnerWindow();if(!treeOwnerAsWin){aError.Throw(NS_ERROR_FAILURE);return;}nsIntSizecssSize(aWidth,aHeight);CheckSecurityWidthAndHeight(&cssSize.width,&cssSize.height,aCallerType);nsIntSizedevSz(CSSToDevIntPixels(cssSize));aError=treeOwnerAsWin->SetSize(devSz.width,devSz.height,true);CheckForDPIChange();}voidnsGlobalWindow::ResizeTo(int32_taWidth,int32_taHeight,CallerTypeaCallerType,ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(ResizeToOuter,(aWidth,aHeight,aCallerType,aError),aError,);}voidnsGlobalWindow::ResizeByOuter(int32_taWidthDif,int32_taHeightDif,CallerTypeaCallerType,ErrorResult&aError){MOZ_RELEASE_ASSERT(IsOuterWindow());/* * If caller is a browser-element then dispatch a resize event to * parent. */if(mDocShell&&mDocShell->GetIsMozBrowser()){CSSIntSizesize;if(NS_FAILED(GetInnerSize(size))){return;}size.width+=aWidthDif;size.height+=aHeightDif;if(!DispatchResizeEvent(size)){// The embedder chose to prevent the default action for this// event, so let's not resize this window after all...return;}}/* * If caller is not chrome and the user has not explicitly exempted the site, * prevent window.resizeBy() by exiting early */if(!CanMoveResizeWindows(aCallerType)||IsFrame()){return;}nsCOMPtr<nsIBaseWindow>treeOwnerAsWin=GetTreeOwnerWindow();if(!treeOwnerAsWin){aError.Throw(NS_ERROR_FAILURE);return;}int32_twidth,height;aError=treeOwnerAsWin->GetSize(&width,&height);if(aError.Failed()){return;}// To do this correctly we have to convert what we got from GetSize// into CSS pixels, add the arguments, do the security check, and// then convert back to device pixels for the call to SetSize.nsIntSizecssSize(DevToCSSIntPixels(nsIntSize(width,height)));cssSize.width+=aWidthDif;cssSize.height+=aHeightDif;CheckSecurityWidthAndHeight(&cssSize.width,&cssSize.height,aCallerType);nsIntSizenewDevSize(CSSToDevIntPixels(cssSize));aError=treeOwnerAsWin->SetSize(newDevSize.width,newDevSize.height,true);CheckForDPIChange();}voidnsGlobalWindow::ResizeBy(int32_taWidthDif,int32_taHeightDif,CallerTypeaCallerType,ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(ResizeByOuter,(aWidthDif,aHeightDif,aCallerType,aError),aError,);}voidnsGlobalWindow::SizeToContentOuter(CallerTypeaCallerType,ErrorResult&aError){MOZ_RELEASE_ASSERT(IsOuterWindow());if(!mDocShell){return;}/* * If caller is not chrome and the user has not explicitly exempted the site, * prevent window.sizeToContent() by exiting early */if(!CanMoveResizeWindows(aCallerType)||IsFrame()){return;}// The content viewer does a check to make sure that it's a content// viewer for a toplevel docshell.nsCOMPtr<nsIContentViewer>cv;mDocShell->GetContentViewer(getter_AddRefs(cv));if(!cv){aError.Throw(NS_ERROR_FAILURE);return;}int32_twidth,height;aError=cv->GetContentSize(&width,&height);if(aError.Failed()){return;}// Make sure the new size is following the CheckSecurityWidthAndHeight// rules.nsCOMPtr<nsIDocShellTreeOwner>treeOwner=GetTreeOwner();if(!treeOwner){aError.Throw(NS_ERROR_FAILURE);return;}nsIntSizecssSize(DevToCSSIntPixels(nsIntSize(width,height)));CheckSecurityWidthAndHeight(&cssSize.width,&cssSize.height,aCallerType);nsIntSizenewDevSize(CSSToDevIntPixels(cssSize));aError=treeOwner->SizeShellTo(mDocShell,newDevSize.width,newDevSize.height);}voidnsGlobalWindow::SizeToContent(CallerTypeaCallerType,ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(SizeToContentOuter,(aCallerType,aError),aError,);}already_AddRefed<nsPIWindowRoot>nsGlobalWindow::GetTopWindowRoot(){nsPIDOMWindowOuter*piWin=GetPrivateRoot();if(!piWin){returnnullptr;}nsCOMPtr<nsPIWindowRoot>window=do_QueryInterface(piWin->GetChromeEventHandler());returnwindow.forget();}voidnsGlobalWindow::Scroll(doubleaXScroll,doubleaYScroll){// Convert -Inf, Inf, and NaN to 0; otherwise, convert by C-style cast.autoscrollPos=CSSIntPoint::Truncate(mozilla::ToZeroIfNonfinite(aXScroll),mozilla::ToZeroIfNonfinite(aYScroll));ScrollTo(scrollPos,ScrollOptions());}voidnsGlobalWindow::ScrollTo(doubleaXScroll,doubleaYScroll){// Convert -Inf, Inf, and NaN to 0; otherwise, convert by C-style cast.autoscrollPos=CSSIntPoint::Truncate(mozilla::ToZeroIfNonfinite(aXScroll),mozilla::ToZeroIfNonfinite(aYScroll));ScrollTo(scrollPos,ScrollOptions());}voidnsGlobalWindow::ScrollTo(constScrollToOptions&aOptions){// When scrolling to a non-zero offset, we need to determine whether that// position is within our scrollable range, so we need updated layout// information which requires a layout flush, otherwise all we need is to// flush frames to be able to access our scrollable frame here.FlushTypeflushType=((aOptions.mLeft.WasPassed()&&aOptions.mLeft.Value()>0)||(aOptions.mTop.WasPassed()&&aOptions.mTop.Value()>0))?FlushType::Layout:FlushType::Frames;FlushPendingNotifications(flushType);nsIScrollableFrame*sf=GetScrollFrame();if(sf){CSSIntPointscrollPos=sf->GetScrollPositionCSSPixels();if(aOptions.mLeft.WasPassed()){scrollPos.x=mozilla::ToZeroIfNonfinite(aOptions.mLeft.Value());}if(aOptions.mTop.WasPassed()){scrollPos.y=mozilla::ToZeroIfNonfinite(aOptions.mTop.Value());}ScrollTo(scrollPos,aOptions);}}voidnsGlobalWindow::Scroll(constScrollToOptions&aOptions){ScrollTo(aOptions);}voidnsGlobalWindow::ScrollTo(constCSSIntPoint&aScroll,constScrollOptions&aOptions){// When scrolling to a non-zero offset, we need to determine whether that// position is within our scrollable range, so we need updated layout// information which requires a layout flush, otherwise all we need is to// flush frames to be able to access our scrollable frame here.FlushTypeflushType=(aScroll.x||aScroll.y)?FlushType::Layout:FlushType::Frames;FlushPendingNotifications(flushType);nsIScrollableFrame*sf=GetScrollFrame();if(sf){// Here we calculate what the max pixel value is that we can// scroll to, we do this by dividing maxint with the pixel to// twips conversion factor, and subtracting 4, the 4 comes from// experimenting with this value, anything less makes the view// code not scroll correctly, I have no idea why. -- jstconstint32_tmaxpx=nsPresContext::AppUnitsToIntCSSPixels(0x7fffffff)-4;CSSIntPointscroll(aScroll);if(scroll.x>maxpx){scroll.x=maxpx;}if(scroll.y>maxpx){scroll.y=maxpx;}boolsmoothScroll=sf->GetScrollbarStyles().IsSmoothScroll(aOptions.mBehavior);sf->ScrollToCSSPixels(scroll,smoothScroll?nsIScrollableFrame::SMOOTH_MSD:nsIScrollableFrame::INSTANT);}}voidnsGlobalWindow::ScrollBy(doubleaXScrollDif,doubleaYScrollDif){FlushPendingNotifications(FlushType::Layout);nsIScrollableFrame*sf=GetScrollFrame();if(sf){// Convert -Inf, Inf, and NaN to 0; otherwise, convert by C-style cast.autoscrollDif=CSSIntPoint::Truncate(mozilla::ToZeroIfNonfinite(aXScrollDif),mozilla::ToZeroIfNonfinite(aYScrollDif));// It seems like it would make more sense for ScrollBy to use// SMOOTH mode, but tests seem to depend on the synchronous behaviour.// Perhaps Web content does too.ScrollTo(sf->GetScrollPositionCSSPixels()+scrollDif,ScrollOptions());}}voidnsGlobalWindow::ScrollBy(constScrollToOptions&aOptions){FlushPendingNotifications(FlushType::Layout);nsIScrollableFrame*sf=GetScrollFrame();if(sf){CSSIntPointscrollPos=sf->GetScrollPositionCSSPixels();if(aOptions.mLeft.WasPassed()){scrollPos.x+=mozilla::ToZeroIfNonfinite(aOptions.mLeft.Value());}if(aOptions.mTop.WasPassed()){scrollPos.y+=mozilla::ToZeroIfNonfinite(aOptions.mTop.Value());}ScrollTo(scrollPos,aOptions);}}voidnsGlobalWindow::ScrollByLines(int32_tnumLines,constScrollOptions&aOptions){MOZ_ASSERT(IsInnerWindow());FlushPendingNotifications(FlushType::Layout);nsIScrollableFrame*sf=GetScrollFrame();if(sf){// It seems like it would make more sense for ScrollByLines to use// SMOOTH mode, but tests seem to depend on the synchronous behaviour.// Perhaps Web content does too.boolsmoothScroll=sf->GetScrollbarStyles().IsSmoothScroll(aOptions.mBehavior);sf->ScrollBy(nsIntPoint(0,numLines),nsIScrollableFrame::LINES,smoothScroll?nsIScrollableFrame::SMOOTH_MSD:nsIScrollableFrame::INSTANT);}}voidnsGlobalWindow::ScrollByPages(int32_tnumPages,constScrollOptions&aOptions){MOZ_ASSERT(IsInnerWindow());FlushPendingNotifications(FlushType::Layout);nsIScrollableFrame*sf=GetScrollFrame();if(sf){// It seems like it would make more sense for ScrollByPages to use// SMOOTH mode, but tests seem to depend on the synchronous behaviour.// Perhaps Web content does too.boolsmoothScroll=sf->GetScrollbarStyles().IsSmoothScroll(aOptions.mBehavior);sf->ScrollBy(nsIntPoint(0,numPages),nsIScrollableFrame::PAGES,smoothScroll?nsIScrollableFrame::SMOOTH_MSD:nsIScrollableFrame::INSTANT);}}voidnsGlobalWindow::MozScrollSnap(){MOZ_ASSERT(IsInnerWindow());FlushPendingNotifications(FlushType::Layout);nsIScrollableFrame*sf=GetScrollFrame();if(sf){sf->ScrollSnap();}}voidnsGlobalWindow::ClearTimeout(int32_taHandle){MOZ_RELEASE_ASSERT(IsInnerWindow());if(aHandle>0){mTimeoutManager->ClearTimeout(aHandle,Timeout::Reason::eTimeoutOrInterval);}}voidnsGlobalWindow::ClearInterval(int32_taHandle){MOZ_RELEASE_ASSERT(IsInnerWindow());if(aHandle>0){mTimeoutManager->ClearTimeout(aHandle,Timeout::Reason::eTimeoutOrInterval);}}voidnsGlobalWindow::SetResizable(boolaResizable)const{// nop}voidnsGlobalWindow::CaptureEvents(){if(mDoc){mDoc->WarnOnceAbout(nsIDocument::eUseOfCaptureEvents);}}voidnsGlobalWindow::ReleaseEvents(){if(mDoc){mDoc->WarnOnceAbout(nsIDocument::eUseOfReleaseEvents);}}staticboolIsPopupBlocked(nsIDocument*aDoc){nsCOMPtr<nsIPopupWindowManager>pm=do_GetService(NS_POPUPWINDOWMANAGER_CONTRACTID);if(!pm){returnfalse;}if(!aDoc){returntrue;}uint32_tpermission=nsIPopupWindowManager::ALLOW_POPUP;pm->TestPermission(aDoc->NodePrincipal(),&permission);returnpermission==nsIPopupWindowManager::DENY_POPUP;}voidnsGlobalWindow::FirePopupBlockedEvent(nsIDocument*aDoc,nsIURI*aPopupURI,constnsAString&aPopupWindowName,constnsAString&aPopupWindowFeatures){MOZ_ASSERT(aDoc);// Fire a "DOMPopupBlocked" event so that the UI can hear about// blocked popups.PopupBlockedEventInitinit;init.mBubbles=true;init.mCancelable=true;init.mRequestingWindow=this;init.mPopupWindowURI=aPopupURI;init.mPopupWindowName=aPopupWindowName;init.mPopupWindowFeatures=aPopupWindowFeatures;RefPtr<PopupBlockedEvent>event=PopupBlockedEvent::Constructor(aDoc,NS_LITERAL_STRING("DOMPopupBlocked"),init);event->SetTrusted(true);booldefaultActionEnabled;aDoc->DispatchEvent(event,&defaultActionEnabled);}// staticboolnsGlobalWindow::CanSetProperty(constchar*aPrefName){// Chrome can set any property.if(nsContentUtils::LegacyIsCallerChromeOrNativeCode()){returntrue;}// If the pref is set to true, we can not set the property// and vice versa.return!Preferences::GetBool(aPrefName,true);}boolnsGlobalWindow::PopupWhitelisted(){if(!IsPopupBlocked(mDoc))returntrue;nsCOMPtr<nsPIDOMWindowOuter>parent=GetParent();if(parent==AsOuter()){returnfalse;}returnnsGlobalWindow::Cast(parent)->PopupWhitelisted();}/* * Examine the current document state to see if we're in a way that is * typically abused by web designers. The window.open code uses this * routine to determine whether to allow the new window. * Returns a value from the PopupControlState enum. */PopupControlStatensGlobalWindow::RevisePopupAbuseLevel(PopupControlStateaControl){MOZ_ASSERT(IsOuterWindow());NS_ASSERTION(mDocShell,"Must have docshell");if(mDocShell->ItemType()!=nsIDocShellTreeItem::typeContent){returnopenAllowed;}PopupControlStateabuse=aControl;switch(abuse){caseopenControlled:caseopenAbused:caseopenOverridden:if(PopupWhitelisted())abuse=PopupControlState(abuse-1);break;caseopenAllowed:break;default:NS_WARNING("Strange PopupControlState!");}// limit the number of simultaneously open popupsif(abuse==openAbused||abuse==openControlled){int32_tpopupMax=Preferences::GetInt("dom.popup_maximum",-1);if(popupMax>=0&&gOpenPopupSpamCount>=popupMax)abuse=openOverridden;}returnabuse;}/* If a window open is blocked, fire the appropriate DOM events. */voidnsGlobalWindow::FireAbuseEvents(constnsAString&aPopupURL,constnsAString&aPopupWindowName,constnsAString&aPopupWindowFeatures){// fetch the URI of the window requesting the opened windownsCOMPtr<nsPIDOMWindowOuter>window=GetTop();if(!window){return;}nsCOMPtr<nsIDocument>topDoc=window->GetDoc();nsCOMPtr<nsIURI>popupURI;// build the URI of the would-have-been popup window// (see nsWindowWatcher::URIfromURL)// first, fetch the opener's base URInsIURI*baseURL=nullptr;nsCOMPtr<nsIDocument>doc=GetEntryDocument();if(doc)baseURL=doc->GetDocBaseURI();// use the base URI to build what would have been the popup's URInsCOMPtr<nsIIOService>ios(do_GetService(NS_IOSERVICE_CONTRACTID));if(ios)ios->NewURI(NS_ConvertUTF16toUTF8(aPopupURL),nullptr,baseURL,getter_AddRefs(popupURI));// fire an event chock full of informative URIsFirePopupBlockedEvent(topDoc,popupURI,aPopupWindowName,aPopupWindowFeatures);}already_AddRefed<nsPIDOMWindowOuter>nsGlobalWindow::OpenOuter(constnsAString&aUrl,constnsAString&aName,constnsAString&aOptions,ErrorResult&aError){MOZ_RELEASE_ASSERT(IsOuterWindow());nsCOMPtr<nsPIDOMWindowOuter>window;aError=OpenJS(aUrl,aName,aOptions,getter_AddRefs(window));returnwindow.forget();}already_AddRefed<nsPIDOMWindowOuter>nsGlobalWindow::Open(constnsAString&aUrl,constnsAString&aName,constnsAString&aOptions,ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(OpenOuter,(aUrl,aName,aOptions,aError),aError,nullptr);}nsresultnsGlobalWindow::Open(constnsAString&aUrl,constnsAString&aName,constnsAString&aOptions,nsIDocShellLoadInfo*aLoadInfo,boolaForceNoOpener,nsPIDOMWindowOuter**_retval){FORWARD_TO_OUTER(Open,(aUrl,aName,aOptions,aLoadInfo,aForceNoOpener,_retval),NS_ERROR_NOT_INITIALIZED);returnOpenInternal(aUrl,aName,aOptions,false,// aDialogfalse,// aContentModaltrue,// aCalledNoScriptfalse,// aDoJSFixupstrue,// aNavigatenullptr,nullptr,// No argsaLoadInfo,aForceNoOpener,_retval);}nsresultnsGlobalWindow::OpenJS(constnsAString&aUrl,constnsAString&aName,constnsAString&aOptions,nsPIDOMWindowOuter**_retval){MOZ_ASSERT(IsOuterWindow());returnOpenInternal(aUrl,aName,aOptions,false,// aDialogfalse,// aContentModalfalse,// aCalledNoScripttrue,// aDoJSFixupstrue,// aNavigatenullptr,nullptr,// No argsnullptr,// aLoadInfofalse,// aForceNoOpener_retval);}// like Open, but attaches to the new window any extra parameters past// [features] as a JS property named "arguments"nsresultnsGlobalWindow::OpenDialog(constnsAString&aUrl,constnsAString&aName,constnsAString&aOptions,nsISupports*aExtraArgument,nsPIDOMWindowOuter**_retval){MOZ_ASSERT(IsOuterWindow());returnOpenInternal(aUrl,aName,aOptions,true,// aDialogfalse,// aContentModaltrue,// aCalledNoScriptfalse,// aDoJSFixupstrue,// aNavigatenullptr,aExtraArgument,// Argumentsnullptr,// aLoadInfofalse,// aForceNoOpener_retval);}// Like Open, but passes aNavigate=false./* virtual */nsresultnsGlobalWindow::OpenNoNavigate(constnsAString&aUrl,constnsAString&aName,constnsAString&aOptions,nsPIDOMWindowOuter**_retval){MOZ_ASSERT(IsOuterWindow());returnOpenInternal(aUrl,aName,aOptions,false,// aDialogfalse,// aContentModaltrue,// aCalledNoScriptfalse,// aDoJSFixupsfalse,// aNavigatenullptr,nullptr,// No argsnullptr,// aLoadInfofalse,// aForceNoOpener_retval);}already_AddRefed<nsPIDOMWindowOuter>nsGlobalWindow::OpenDialogOuter(JSContext*aCx,constnsAString&aUrl,constnsAString&aName,constnsAString&aOptions,constSequence<JS::Value>&aExtraArgument,ErrorResult&aError){MOZ_RELEASE_ASSERT(IsOuterWindow());nsCOMPtr<nsIJSArgArray>argvArray;aError=NS_CreateJSArgv(aCx,aExtraArgument.Length(),aExtraArgument.Elements(),getter_AddRefs(argvArray));if(aError.Failed()){returnnullptr;}nsCOMPtr<nsPIDOMWindowOuter>dialog;aError=OpenInternal(aUrl,aName,aOptions,true,// aDialogfalse,// aContentModalfalse,// aCalledNoScriptfalse,// aDoJSFixupstrue,// aNavigateargvArray,nullptr,// Argumentsnullptr,// aLoadInfofalse,// aForceNoOpenergetter_AddRefs(dialog));returndialog.forget();}already_AddRefed<nsPIDOMWindowOuter>nsGlobalWindow::OpenDialog(JSContext*aCx,constnsAString&aUrl,constnsAString&aName,constnsAString&aOptions,constSequence<JS::Value>&aExtraArgument,ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(OpenDialogOuter,(aCx,aUrl,aName,aOptions,aExtraArgument,aError),aError,nullptr);}already_AddRefed<nsPIDOMWindowOuter>nsGlobalWindow::GetFramesOuter(){RefPtr<nsPIDOMWindowOuter>frames(AsOuter());FlushPendingNotifications(FlushType::ContentAndNotify);returnframes.forget();}already_AddRefed<nsPIDOMWindowOuter>nsGlobalWindow::GetFrames(ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(GetFramesOuter,(),aError,nullptr);}nsGlobalWindow*nsGlobalWindow::CallerInnerWindow(){JSContext*cx=nsContentUtils::GetCurrentJSContext();NS_ENSURE_TRUE(cx,nullptr);nsIGlobalObject*global=GetIncumbentGlobal();NS_ENSURE_TRUE(global,nullptr);JS::Rooted<JSObject*>scope(cx,global->GetGlobalJSObject());NS_ENSURE_TRUE(scope,nullptr);// When Jetpack runs content scripts inside a sandbox, it uses// sandboxPrototype to make them appear as though they're running in the// scope of the page. So when a content script invokes postMessage, it expects// the |source| of the received message to be the window set as the// sandboxPrototype. This used to work incidentally for unrelated reasons, but// now we need to do some special handling to support it.if(xpc::IsSandbox(scope)){JSAutoCompartmentac(cx,scope);JS::Rooted<JSObject*>scopeProto(cx);boolok=JS_GetPrototype(cx,scope,&scopeProto);NS_ENSURE_TRUE(ok,nullptr);if(scopeProto&&xpc::IsSandboxPrototypeProxy(scopeProto)&&(scopeProto=js::CheckedUnwrap(scopeProto,/* stopAtWindowProxy = */false))){global=xpc::NativeGlobal(scopeProto);NS_ENSURE_TRUE(global,nullptr);}}// The calling window must be holding a reference, so we can return a weak// pointer.nsCOMPtr<nsPIDOMWindowInner>win=do_QueryInterface(global);returnnsGlobalWindow::Cast(win);}voidnsGlobalWindow::PostMessageMozOuter(JSContext*aCx,JS::Handle<JS::Value>aMessage,constnsAString&aTargetOrigin,JS::Handle<JS::Value>aTransfer,nsIPrincipal&aSubjectPrincipal,ErrorResult&aError){MOZ_RELEASE_ASSERT(IsOuterWindow());//// Window.postMessage is an intentional subversion of the same-origin policy.// As such, this code must be particularly careful in the information it// exposes to calling code.//// http://www.whatwg.org/specs/web-apps/current-work/multipage/section-crossDocumentMessages.html//// First, get the caller's windowRefPtr<nsGlobalWindow>callerInnerWin=CallerInnerWindow();nsIPrincipal*callerPrin;if(callerInnerWin){MOZ_ASSERT(callerInnerWin->IsInnerWindow(),"should have gotten an inner window here");// Compute the caller's origin either from its principal or, in the case the// principal doesn't carry a URI (e.g. the system principal), the caller's// document. We must get this now instead of when the event is created and// dispatched, because ultimately it is the identity of the calling window// *now* that determines who sent the message (and not an identity which might// have changed due to intervening navigations).callerPrin=callerInnerWin->GetPrincipal();}else{// In case the global is not a window, it can be a sandbox, and the sandbox's// principal can be used for the security check.nsIGlobalObject*global=GetIncumbentGlobal();NS_ASSERTION(global,"Why is there no global object?");callerPrin=global->PrincipalOrNull();}if(!callerPrin){return;}nsCOMPtr<nsIURI>callerOuterURI;if(NS_FAILED(callerPrin->GetURI(getter_AddRefs(callerOuterURI)))){return;}nsAutoStringorigin;if(callerOuterURI){// if the principal has a URI, use that to generate the originnsContentUtils::GetUTFOrigin(callerPrin,origin);}elseif(callerInnerWin){// otherwise use the URI of the document to generate originnsCOMPtr<nsIDocument>doc=callerInnerWin->GetExtantDoc();if(!doc){return;}callerOuterURI=doc->GetDocumentURI();// if the principal has a URI, use that to generate the originnsContentUtils::GetUTFOrigin(callerOuterURI,origin);}else{// in case of a sandbox with a system principal origin can be emptyif(!nsContentUtils::IsSystemPrincipal(callerPrin)){return;}}// Convert the provided origin string into a URI for comparison purposes.nsCOMPtr<nsIPrincipal>providedPrincipal;if(aTargetOrigin.EqualsASCII("/")){providedPrincipal=callerPrin;}// "*" indicates no specific origin is required.elseif(!aTargetOrigin.EqualsASCII("*")){nsCOMPtr<nsIURI>originURI;if(NS_FAILED(NS_NewURI(getter_AddRefs(originURI),aTargetOrigin))){aError.Throw(NS_ERROR_DOM_SYNTAX_ERR);return;}if(NS_FAILED(originURI->SetUserPass(EmptyCString()))||NS_FAILED(originURI->SetPath(EmptyCString()))){return;}OriginAttributesattrs=aSubjectPrincipal.OriginAttributesRef();if(aSubjectPrincipal.GetIsSystemPrincipal()){autoprincipal=BasePrincipal::Cast(GetPrincipal());if(attrs!=principal->OriginAttributesRef()){nsCOMPtr<nsIURI>targetURI;nsAutoCStringtargetURL;nsAutoCStringsourceOrigin;nsAutoCStringtargetOrigin;if(NS_FAILED(principal->GetURI(getter_AddRefs(targetURI)))||NS_FAILED(targetURI->GetAsciiSpec(targetURL))||NS_FAILED(principal->GetOrigin(targetOrigin))||NS_FAILED(aSubjectPrincipal.GetOrigin(sourceOrigin))){NS_WARNING("Failed to get source and target origins");return;}nsContentUtils::LogSimpleConsoleError(NS_ConvertUTF8toUTF16(nsPrintfCString(R"(Attempting to post a message to window with url "%s" and )"R"(origin "%s" from a system principal scope with mismatched )"R"(origin "%s".)",targetURL.get(),targetOrigin.get(),sourceOrigin.get())),"DOM");attrs=principal->OriginAttributesRef();}}// Create a nsIPrincipal inheriting the app/browser attributes from the// caller.providedPrincipal=BasePrincipal::CreateCodebasePrincipal(originURI,attrs);if(NS_WARN_IF(!providedPrincipal)){return;}}// Create and asynchronously dispatch a runnable which will handle actual DOM// event creation and dispatch.RefPtr<PostMessageEvent>event=newPostMessageEvent(nsContentUtils::IsCallerChrome()||!callerInnerWin?nullptr:callerInnerWin->GetOuterWindowInternal(),origin,this,providedPrincipal,callerInnerWin?callerInnerWin->GetDoc():nullptr,nsContentUtils::IsCallerChrome());JS::Rooted<JS::Value>message(aCx,aMessage);JS::Rooted<JS::Value>transfer(aCx,aTransfer);event->Write(aCx,message,transfer,JS::CloneDataPolicy(),aError);if(NS_WARN_IF(aError.Failed())){return;}aError=Dispatch("PostMessageEvent",TaskCategory::Other,event.forget());}voidnsGlobalWindow::PostMessageMoz(JSContext*aCx,JS::Handle<JS::Value>aMessage,constnsAString&aTargetOrigin,JS::Handle<JS::Value>aTransfer,nsIPrincipal&aSubjectPrincipal,ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(PostMessageMozOuter,(aCx,aMessage,aTargetOrigin,aTransfer,aSubjectPrincipal,aError),aError,);}voidnsGlobalWindow::PostMessageMoz(JSContext*aCx,JS::Handle<JS::Value>aMessage,constnsAString&aTargetOrigin,constSequence<JSObject*>&aTransfer,nsIPrincipal&aSubjectPrincipal,ErrorResult&aRv){JS::Rooted<JS::Value>transferArray(aCx,JS::UndefinedValue());aRv=nsContentUtils::CreateJSValueFromSequenceOfObject(aCx,aTransfer,&transferArray);if(NS_WARN_IF(aRv.Failed())){return;}PostMessageMoz(aCx,aMessage,aTargetOrigin,transferArray,aSubjectPrincipal,aRv);}classnsCloseEvent:publicRunnable{RefPtr<nsGlobalWindow>mWindow;boolmIndirect;nsCloseEvent(nsGlobalWindow*aWindow,boolaIndirect):mozilla::Runnable("nsCloseEvent"),mWindow(aWindow),mIndirect(aIndirect){}public:staticnsresultPostCloseEvent(nsGlobalWindow*aWindow,boolaIndirect){nsCOMPtr<nsIRunnable>ev=newnsCloseEvent(aWindow,aIndirect);nsresultrv=aWindow->Dispatch("nsCloseEvent",TaskCategory::Other,ev.forget());if(NS_SUCCEEDED(rv))aWindow->MaybeForgiveSpamCount();returnrv;}NS_IMETHODRun()override{if(mWindow){if(mIndirect){returnPostCloseEvent(mWindow,false);}mWindow->ReallyCloseWindow();}returnNS_OK;}};boolnsGlobalWindow::CanClose(){MOZ_ASSERT(IsOuterWindow());if(mIsChrome){nsCOMPtr<nsIBrowserDOMWindow>bwin;nsIDOMChromeWindow*chromeWin=static_cast<nsGlobalChromeWindow*>(this);chromeWin->GetBrowserDOMWindow(getter_AddRefs(bwin));boolcanClose=true;if(bwin&&NS_SUCCEEDED(bwin->CanClose(&canClose))){returncanClose;}}if(!mDocShell){returntrue;}// Ask the content viewer whether the toplevel window can close.// If the content viewer returns false, it is responsible for calling// Close() as soon as it is possible for the window to close.// This allows us to not close the window while printing is happening.nsCOMPtr<nsIContentViewer>cv;mDocShell->GetContentViewer(getter_AddRefs(cv));if(cv){boolcanClose;nsresultrv=cv->PermitUnload(&canClose);if(NS_SUCCEEDED(rv)&&!canClose)returnfalse;rv=cv->RequestWindowClose(&canClose);if(NS_SUCCEEDED(rv)&&!canClose)returnfalse;}returntrue;}voidnsGlobalWindow::CloseOuter(boolaTrustedCaller){MOZ_RELEASE_ASSERT(IsOuterWindow());if(!mDocShell||IsInModalState()||(IsFrame()&&!mDocShell->GetIsMozBrowser())){// window.close() is called on a frame in a frameset, on a window// that's already closed, or on a window for which there's// currently a modal dialog open. Ignore such calls.return;}if(mHavePendingClose){// We're going to be closed anyway; do nothing since we don't want// to double-closereturn;}if(mBlockScriptedClosingFlag){// A script's popup has been blocked and we don't want// the window to be closed directly after this event,// so the user can see that there was a blocked popup.return;}// Don't allow scripts from content to close non-neterror windows that// were not opened by script.nsAutoStringurl;nsresultrv=mDoc->GetURL(url);NS_ENSURE_SUCCESS_VOID(rv);if(!StringBeginsWith(url,NS_LITERAL_STRING("about:neterror"))&&!mHadOriginalOpener&&!aTrustedCaller){boolallowClose=mAllowScriptsToClose||Preferences::GetBool("dom.allow_scripts_to_close_windows",true);if(!allowClose){// We're blocking the close operation// report localized error msg in JS consolensContentUtils::ReportToConsole(nsIScriptError::warningFlag,NS_LITERAL_CSTRING("DOM Window"),mDoc,// Better name for the category?nsContentUtils::eDOM_PROPERTIES,"WindowCloseBlockedWarning");return;}}if(!mInClose&&!mIsClosed&&!CanClose()){return;}// Fire a DOM event notifying listeners that this window is about to// be closed. The tab UI code may choose to cancel the default// action for this event, if so, we won't actually close the window// (since the tab UI code will close the tab in stead). Sure, this// could be abused by content code, but do we care? I don't think// so...boolwasInClose=mInClose;mInClose=true;if(!DispatchCustomEvent(NS_LITERAL_STRING("DOMWindowClose"))){// Someone chose to prevent the default action for this event, if// so, let's not close this window after all...mInClose=wasInClose;return;}FinalClose();}voidnsGlobalWindow::Close(ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(CloseOuter,(nsContentUtils::IsCallerChrome()),aError,);}nsresultnsGlobalWindow::Close(){FORWARD_TO_OUTER(Close,(),NS_ERROR_UNEXPECTED);CloseOuter(/* aTrustedCaller = */true);returnNS_OK;}voidnsGlobalWindow::ForceClose(){MOZ_ASSERT(IsOuterWindow());MOZ_ASSERT(XRE_GetProcessType()==GeckoProcessType_Default);if(IsFrame()||!mDocShell){// This may be a frame in a frameset, or a window that's already closed.// Ignore such calls.return;}if(mHavePendingClose){// We're going to be closed anyway; do nothing since we don't want// to double-closereturn;}mInClose=true;DispatchCustomEvent(NS_LITERAL_STRING("DOMWindowClose"));FinalClose();}voidnsGlobalWindow::FinalClose(){MOZ_ASSERT(IsOuterWindow());// Flag that we were closed.mIsClosed=true;// If we get here from CloseOuter then it means that the parent process is// going to close our window for us. It's just important to set mIsClosed.if(XRE_GetProcessType()==GeckoProcessType_Content){return;}// This stuff is non-sensical but incredibly fragile. The reasons for the// behavior here don't make sense today and may not have ever made sense,// but various bits of frontend code break when you change them. If you need// to fix up this behavior, feel free to. It's a righteous task, but involves// wrestling with various download manager tests, frontend code, and possible// broken addons. The chrome tests in toolkit/mozapps/downloads are a good// testing ground.//// In particular, if some inner of |win| is the entry global, we must// complete _two_ round-trips to the event loop before the call to// ReallyCloseWindow. This allows setTimeout handlers that are set after// FinalClose() is called to run before the window is torn down.nsCOMPtr<nsPIDOMWindowInner>entryWindow=do_QueryInterface(GetEntryGlobal());boolindirect=entryWindow&&entryWindow->GetOuterWindow()==this->AsOuter();if(NS_FAILED(nsCloseEvent::PostCloseEvent(this,indirect))){ReallyCloseWindow();}else{mHavePendingClose=true;}}voidnsGlobalWindow::ReallyCloseWindow(){FORWARD_TO_OUTER_VOID(ReallyCloseWindow,());// Make sure we never reenter this method.mHavePendingClose=true;nsCOMPtr<nsIBaseWindow>treeOwnerAsWin=GetTreeOwnerWindow();// If there's no treeOwnerAsWin, this window must already be closed.if(treeOwnerAsWin){// but if we're a browser window we could be in some nasty// self-destroying cascade that we should mostly ignoreif(mDocShell){nsCOMPtr<nsIBrowserDOMWindow>bwin;nsCOMPtr<nsIDocShellTreeItem>rootItem;mDocShell->GetRootTreeItem(getter_AddRefs(rootItem));nsCOMPtr<nsPIDOMWindowOuter>rootWin=rootItem?rootItem->GetWindow():nullptr;nsCOMPtr<nsIDOMChromeWindow>chromeWin(do_QueryInterface(rootWin));if(chromeWin)chromeWin->GetBrowserDOMWindow(getter_AddRefs(bwin));if(rootWin){/* Normally we destroy the entire window, but not if this DOM window belongs to a tabbed browser and doesn't correspond to a tab. This allows a well-behaved tab to destroy the container as it should but is a final measure to prevent an errant tab from doing so when it shouldn't. This works because we reach this code when we shouldn't only in the particular circumstance that we belong to a tab that has just been closed (and is therefore already missing from the list of browsers) (and has an unload handler that closes the window). */// XXXbz now that we have mHavePendingClose, is this needed?boolisTab;if(rootWin==AsOuter()||!bwin||(NS_SUCCEEDED(bwin->IsTabContentWindow(GetOuterWindowInternal(),&isTab))&&isTab)){treeOwnerAsWin->Destroy();}}}CleanUp();}}voidnsGlobalWindow::EnterModalState(){MOZ_ASSERT(IsOuterWindow(),"Modal state is maintained on outer windows");// GetScriptableTop, not GetTop, so that EnterModalState works properly with// <iframe mozbrowser>.nsGlobalWindow*topWin=GetScriptableTopInternal();if(!topWin){NS_ERROR("Uh, EnterModalState() called w/o a reachable top window?");return;}// If there is an active ESM in this window, clear it. Otherwise, this can// cause a problem if a modal state is entered during a mouseup event.EventStateManager*activeESM=static_cast<EventStateManager*>(EventStateManager::GetActiveEventStateManager());if(activeESM&&activeESM->GetPresContext()){nsIPresShell*activeShell=activeESM->GetPresContext()->GetPresShell();if(activeShell&&(nsContentUtils::ContentIsCrossDocDescendantOf(activeShell->GetDocument(),mDoc)||nsContentUtils::ContentIsCrossDocDescendantOf(mDoc,activeShell->GetDocument()))){EventStateManager::ClearGlobalActiveContent(activeESM);activeShell->SetCapturingContent(nullptr,0);if(activeShell){RefPtr<nsFrameSelection>frameSelection=activeShell->FrameSelection();frameSelection->SetDragState(false);}}}// If there are any drag and drop operations in flight, try to end them.nsCOMPtr<nsIDragService>ds=do_GetService("@mozilla.org/widget/dragservice;1");if(ds){ds->EndDragSession(true,0);}// Clear the capturing content if it is under topDoc.// Usually the activeESM check above does that, but there are cases when// we don't have activeESM, or it is for different document.nsIDocument*topDoc=topWin->GetExtantDoc();nsIContent*capturingContent=nsIPresShell::GetCapturingContent();if(capturingContent&&topDoc&&nsContentUtils::ContentIsCrossDocDescendantOf(capturingContent,topDoc)){nsIPresShell::SetCapturingContent(nullptr,0);}if(topWin->mModalStateDepth==0){NS_ASSERTION(!topWin->mSuspendedDoc,"Shouldn't have mSuspendedDoc here!");topWin->mSuspendedDoc=topDoc;if(topDoc){topDoc->SuppressEventHandling();}nsGlobalWindow*inner=topWin->GetCurrentInnerWindowInternal();if(inner){topWin->GetCurrentInnerWindowInternal()->Suspend();}}topWin->mModalStateDepth++;}voidnsGlobalWindow::LeaveModalState(){MOZ_ASSERT(IsOuterWindow(),"Modal state is maintained on outer windows");nsGlobalWindow*topWin=GetScriptableTopInternal();if(!topWin){NS_ERROR("Uh, LeaveModalState() called w/o a reachable top window?");return;}MOZ_ASSERT(topWin->mModalStateDepth!=0);MOZ_ASSERT(IsSuspended());MOZ_ASSERT(topWin->IsSuspended());topWin->mModalStateDepth--;nsGlobalWindow*inner=topWin->GetCurrentInnerWindowInternal();if(topWin->mModalStateDepth==0){if(inner){inner->Resume();}if(topWin->mSuspendedDoc){nsCOMPtr<nsIDocument>currentDoc=topWin->GetExtantDoc();topWin->mSuspendedDoc->UnsuppressEventHandlingAndFireEvents(currentDoc==topWin->mSuspendedDoc);topWin->mSuspendedDoc=nullptr;}}// Remember the time of the last dialog quit.if(inner){inner->mLastDialogQuitTime=TimeStamp::Now();}if(topWin->mModalStateDepth==0){RefPtr<Event>event=NS_NewDOMEvent(inner,nullptr,nullptr);event->InitEvent(NS_LITERAL_STRING("endmodalstate"),true,false);event->SetTrusted(true);event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch=true;booldummy;topWin->DispatchEvent(event,&dummy);}}boolnsGlobalWindow::IsInModalState(){nsGlobalWindow*topWin=GetScriptableTopInternal();if(!topWin){// IsInModalState() getting called w/o a reachable top window is a bit// iffy, but valid enough not to make noise about it. See bug 404828returnfalse;}returntopWin->mModalStateDepth!=0;}// staticvoidnsGlobalWindow::NotifyDOMWindowDestroyed(nsGlobalWindow*aWindow){nsCOMPtr<nsIObserverService>observerService=services::GetObserverService();if(observerService){observerService->NotifyObservers(ToSupports(aWindow),DOM_WINDOW_DESTROYED_TOPIC,nullptr);}}// Try to match compartments that are not web content by matching compartments// with principals that are either the system principal or an expanded principal.// This may not return true for all non-web-content compartments.structBrowserCompartmentMatcher:publicjs::CompartmentFilter{boolmatch(JSCompartment*aC)constoverride{nsCOMPtr<nsIPrincipal>pc=nsJSPrincipals::get(JS_GetCompartmentPrincipals(aC));returnnsContentUtils::IsSystemOrExpandedPrincipal(pc);}};classWindowDestroyedEventfinal:publicRunnable{public:WindowDestroyedEvent(nsIDOMWindow*aWindow,uint64_taID,constchar*aTopic):mozilla::Runnable("WindowDestroyedEvent"),mID(aID),mPhase(Phase::Destroying),mTopic(aTopic){mWindow=do_GetWeakReference(aWindow);}enumclassPhase{Destroying,Nuking};NS_IMETHODRun()override{AUTO_PROFILER_LABEL("WindowDestroyedEvent::Run",OTHER);nsCOMPtr<nsIObserverService>observerService=services::GetObserverService();if(!observerService){returnNS_OK;}nsCOMPtr<nsISupportsPRUint64>wrapper=do_CreateInstance(NS_SUPPORTS_PRUINT64_CONTRACTID);if(wrapper){wrapper->SetData(mID);observerService->NotifyObservers(wrapper,mTopic.get(),nullptr);}switch(mPhase){casePhase::Destroying:{boolskipNukeCrossCompartment=false;#ifndef DEBUGnsCOMPtr<nsIAppStartup>appStartup=do_GetService(NS_APPSTARTUP_CONTRACTID);if(appStartup){appStartup->GetShuttingDown(&skipNukeCrossCompartment);}#endifif(!skipNukeCrossCompartment){// The compartment nuking phase might be too expensive, so do that// part off of idle dispatch.// For the compartment nuking phase, we dispatch either an// inner-window-nuked or an outer-window-nuked notification.// This will allow tests to wait for compartment nuking to happen.if(mTopic.EqualsLiteral("inner-window-destroyed")){mTopic.AssignLiteral("inner-window-nuked");}elseif(mTopic.EqualsLiteral("outer-window-destroyed")){mTopic.AssignLiteral("outer-window-nuked");}mPhase=Phase::Nuking;nsCOMPtr<nsIRunnable>copy(this);NS_IdleDispatchToCurrentThread(copy.forget(),1000);}}break;casePhase::Nuking:{nsCOMPtr<nsISupports>window=do_QueryReferent(mWindow);if(window){nsGlobalWindow*win=nsGlobalWindow::FromSupports(window);nsGlobalWindow*currentInner=win->IsInnerWindow()?win:win->GetCurrentInnerWindowInternal();NS_ENSURE_TRUE(currentInner,NS_OK);AutoSafeJSContextcx;JS::Rooted<JSObject*>obj(cx,currentInner->FastGetGlobalJSObject());if(obj&&!js::IsSystemCompartment(js::GetObjectCompartment(obj))){JSCompartment*cpt=js::GetObjectCompartment(obj);nsCOMPtr<nsIPrincipal>pc=nsJSPrincipals::get(JS_GetCompartmentPrincipals(cpt));nsAutoStringaddonId;if(NS_SUCCEEDED(pc->GetAddonId(addonId))&&!addonId.IsEmpty()){// We want to nuke all references to the add-on compartment.xpc::NukeAllWrappersForCompartment(cx,cpt,win->IsInnerWindow()?js::DontNukeWindowReferences:js::NukeWindowReferences);}else{// We only want to nuke wrappers for the chrome->content casejs::NukeCrossCompartmentWrappers(cx,BrowserCompartmentMatcher(),cpt,win->IsInnerWindow()?js::DontNukeWindowReferences:js::NukeWindowReferences,js::NukeIncomingReferences);}}}}break;}returnNS_OK;}private:uint64_tmID;PhasemPhase;nsCStringmTopic;nsWeakPtrmWindow;};voidnsGlobalWindow::NotifyWindowIDDestroyed(constchar*aTopic){nsCOMPtr<nsIRunnable>runnable=newWindowDestroyedEvent(this,mWindowID,aTopic);nsresultrv=Dispatch("WindowDestroyedEvent",TaskCategory::Other,runnable.forget());if(NS_SUCCEEDED(rv)){mNotifiedIDDestroyed=true;}}// staticvoidnsGlobalWindow::NotifyDOMWindowFrozen(nsGlobalWindow*aWindow){if(aWindow&&aWindow->IsInnerWindow()){nsCOMPtr<nsIObserverService>observerService=services::GetObserverService();if(observerService){observerService->NotifyObservers(ToSupports(aWindow),DOM_WINDOW_FROZEN_TOPIC,nullptr);}}}// staticvoidnsGlobalWindow::NotifyDOMWindowThawed(nsGlobalWindow*aWindow){if(aWindow&&aWindow->IsInnerWindow()){nsCOMPtr<nsIObserverService>observerService=services::GetObserverService();if(observerService){observerService->NotifyObservers(ToSupports(aWindow),DOM_WINDOW_THAWED_TOPIC,nullptr);}}}JSObject*nsGlobalWindow::GetCachedXBLPrototypeHandler(nsXBLPrototypeHandler*aKey){JS::Rooted<JSObject*>handler(RootingCx());if(mCachedXBLPrototypeHandlers){mCachedXBLPrototypeHandlers->Get(aKey,handler.address());}returnhandler;}voidnsGlobalWindow::CacheXBLPrototypeHandler(nsXBLPrototypeHandler*aKey,JS::Handle<JSObject*>aHandler){if(!mCachedXBLPrototypeHandlers){mCachedXBLPrototypeHandlers=newXBLPrototypeHandlerTable();PreserveWrapper(ToSupports(this));}mCachedXBLPrototypeHandlers->Put(aKey,aHandler);}Element*nsGlobalWindow::GetFrameElementOuter(nsIPrincipal&aSubjectPrincipal){MOZ_RELEASE_ASSERT(IsOuterWindow());if(!mDocShell||mDocShell->GetIsMozBrowser()){returnnullptr;}// Per HTML5, the frameElement getter returns null in cross-origin situations.Element*element=GetRealFrameElementOuter();if(!element){returnnullptr;}if(!aSubjectPrincipal.SubsumesConsideringDomain(element->NodePrincipal())){returnnullptr;}returnelement;}Element*nsGlobalWindow::GetFrameElement(nsIPrincipal&aSubjectPrincipal,ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(GetFrameElementOuter,(aSubjectPrincipal),aError,nullptr);}Element*nsGlobalWindow::GetRealFrameElementOuter(){MOZ_RELEASE_ASSERT(IsOuterWindow());if(!mDocShell){returnnullptr;}nsCOMPtr<nsIDocShell>parent;mDocShell->GetSameTypeParentIgnoreBrowserBoundaries(getter_AddRefs(parent));if(!parent||parent==mDocShell){// We're at a chrome boundary, don't expose the chrome iframe// element to content code.returnnullptr;}returnmFrameElement;}Element*nsGlobalWindow::GetRealFrameElement(ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(GetRealFrameElementOuter,(),aError,nullptr);}/** * nsIGlobalWindow::GetFrameElement (when called from C++) is just a wrapper * around GetRealFrameElement. */already_AddRefed<nsIDOMElement>nsGlobalWindow::GetFrameElement(){FORWARD_TO_INNER(GetFrameElement,(),nullptr);ErrorResultdummy;nsCOMPtr<nsIDOMElement>frameElement=do_QueryInterface(GetRealFrameElement(dummy));dummy.SuppressException();returnframeElement.forget();}/* static */boolnsGlobalWindow::TokenizeDialogOptions(nsAString&aToken,nsAString::const_iterator&aIter,nsAString::const_iteratoraEnd){while(aIter!=aEnd&&nsCRT::IsAsciiSpace(*aIter)){++aIter;}if(aIter==aEnd){returnfalse;}if(*aIter==';'||*aIter==':'||*aIter=='='){aToken.Assign(*aIter);++aIter;returntrue;}nsAString::const_iteratorstart=aIter;// Skip characters until we find whitespace, ';', ':', or '='while(aIter!=aEnd&&!nsCRT::IsAsciiSpace(*aIter)&&*aIter!=';'&&*aIter!=':'&&*aIter!='='){++aIter;}aToken.Assign(Substring(start,aIter));returntrue;}// Helper for converting window.showModalDialog() options (list of ';'// separated name (:|=) value pairs) to a format that's parsable by// our normal window opening code./* static */voidnsGlobalWindow::ConvertDialogOptions(constnsAString&aOptions,nsAString&aResult){nsAString::const_iteratorend;aOptions.EndReading(end);nsAString::const_iteratoriter;aOptions.BeginReading(iter);nsAutoStringtoken;nsAutoStringname;nsAutoStringvalue;while(true){if(!TokenizeDialogOptions(name,iter,end)){break;}// Invalid name.if(name.EqualsLiteral("=")||name.EqualsLiteral(":")||name.EqualsLiteral(";")){break;}if(!TokenizeDialogOptions(token,iter,end)){break;}if(!token.EqualsLiteral(":")&&!token.EqualsLiteral("=")){continue;}// We found name followed by ':' or '='. Look for a value.if(!TokenizeDialogOptions(value,iter,end)){break;}if(name.LowerCaseEqualsLiteral("center")){if(value.LowerCaseEqualsLiteral("on")||value.LowerCaseEqualsLiteral("yes")||value.LowerCaseEqualsLiteral("1")){aResult.AppendLiteral(",centerscreen=1");}}elseif(name.LowerCaseEqualsLiteral("dialogwidth")){if(!value.IsEmpty()){aResult.AppendLiteral(",width=");aResult.Append(value);}}elseif(name.LowerCaseEqualsLiteral("dialogheight")){if(!value.IsEmpty()){aResult.AppendLiteral(",height=");aResult.Append(value);}}elseif(name.LowerCaseEqualsLiteral("dialogtop")){if(!value.IsEmpty()){aResult.AppendLiteral(",top=");aResult.Append(value);}}elseif(name.LowerCaseEqualsLiteral("dialogleft")){if(!value.IsEmpty()){aResult.AppendLiteral(",left=");aResult.Append(value);}}elseif(name.LowerCaseEqualsLiteral("resizable")){if(value.LowerCaseEqualsLiteral("on")||value.LowerCaseEqualsLiteral("yes")||value.LowerCaseEqualsLiteral("1")){aResult.AppendLiteral(",resizable=1");}}elseif(name.LowerCaseEqualsLiteral("scroll")){if(value.LowerCaseEqualsLiteral("off")||value.LowerCaseEqualsLiteral("no")||value.LowerCaseEqualsLiteral("0")){aResult.AppendLiteral(",scrollbars=0");}}if(iter==end||!TokenizeDialogOptions(token,iter,end)||!token.EqualsLiteral(";")){break;}}}already_AddRefed<nsIVariant>nsGlobalWindow::ShowModalDialogOuter(constnsAString&aUrl,nsIVariant*aArgument,constnsAString&aOptions,nsIPrincipal&aSubjectPrincipal,ErrorResult&aError){MOZ_RELEASE_ASSERT(IsOuterWindow());if(mDoc){mDoc->WarnOnceAbout(nsIDocument::eShowModalDialog);}if(!IsShowModalDialogEnabled()){aError.Throw(NS_ERROR_NOT_AVAILABLE);returnnullptr;}RefPtr<DialogValueHolder>argHolder=newDialogValueHolder(&aSubjectPrincipal,aArgument);// Before bringing up the window/dialog, unsuppress painting and flush// pending reflows.EnsureReflowFlushAndPaint();if(!AreDialogsEnabled()){// We probably want to keep throwing here; silently doing nothing is a bit// weird given the typical use cases of showModalDialog().aError.Throw(NS_ERROR_NOT_AVAILABLE);returnnullptr;}if(ShouldPromptToBlockDialogs()&&!ConfirmDialogIfNeeded()){aError.Throw(NS_ERROR_NOT_AVAILABLE);returnnullptr;}nsCOMPtr<nsPIDOMWindowOuter>dlgWin;nsAutoStringoptions(NS_LITERAL_STRING("-moz-internal-modal=1,status=1"));ConvertDialogOptions(aOptions,options);options.AppendLiteral(",scrollbars=1,centerscreen=1,resizable=0");EnterModalState();uint32_toldMicroTaskLevel=nsContentUtils::MicroTaskLevel();nsContentUtils::SetMicroTaskLevel(0);aError=OpenInternal(aUrl,EmptyString(),options,false,// aDialogtrue,// aContentModaltrue,// aCalledNoScripttrue,// aDoJSFixupstrue,// aNavigatenullptr,argHolder,// argsnullptr,// aLoadInfofalse,// aForceNoOpenergetter_AddRefs(dlgWin));nsContentUtils::SetMicroTaskLevel(oldMicroTaskLevel);LeaveModalState();if(aError.Failed()){returnnullptr;}nsCOMPtr<nsIDOMModalContentWindow>dialog=do_QueryInterface(dlgWin);if(!dialog){returnnullptr;}nsCOMPtr<nsIVariant>retVal;aError=dialog->GetReturnValue(getter_AddRefs(retVal));MOZ_ASSERT(!aError.Failed());returnretVal.forget();}already_AddRefed<nsIVariant>nsGlobalWindow::ShowModalDialog(constnsAString&aUrl,nsIVariant*aArgument,constnsAString&aOptions,nsIPrincipal&aSubjectPrincipal,ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(ShowModalDialogOuter,(aUrl,aArgument,aOptions,aSubjectPrincipal,aError),aError,nullptr);}voidnsGlobalWindow::ShowModalDialog(JSContext*aCx,constnsAString&aUrl,JS::Handle<JS::Value>aArgument,constnsAString&aOptions,JS::MutableHandle<JS::Value>aRetval,nsIPrincipal&aSubjectPrincipal,ErrorResult&aError){MOZ_ASSERT(IsInnerWindow());nsCOMPtr<nsIVariant>args;aError=nsContentUtils::XPConnect()->JSToVariant(aCx,aArgument,getter_AddRefs(args));if(aError.Failed()){return;}nsCOMPtr<nsIVariant>retVal=ShowModalDialog(aUrl,args,aOptions,aSubjectPrincipal,aError);if(aError.Failed()){return;}JS::Rooted<JS::Value>result(aCx);if(retVal){JS::Rooted<JSObject*>global(aCx,JS::CurrentGlobalOrNull(aCx));if(!global){global=FastGetGlobalJSObject();}aError=nsContentUtils::XPConnect()->VariantToJS(aCx,global,retVal,aRetval);}else{aRetval.setNull();}}classChildCommandDispatcher:publicRunnable{public:ChildCommandDispatcher(nsGlobalWindow*aWindow,nsITabChild*aTabChild,constnsAString&aAction):mozilla::Runnable("ChildCommandDispatcher"),mWindow(aWindow),mTabChild(aTabChild),mAction(aAction){}NS_IMETHODRun()override{nsCOMPtr<nsPIWindowRoot>root=mWindow->GetTopWindowRoot();if(!root){returnNS_OK;}nsTArray<nsCString>enabledCommands,disabledCommands;root->GetEnabledDisabledCommands(enabledCommands,disabledCommands);if(enabledCommands.Length()||disabledCommands.Length()){mTabChild->EnableDisableCommands(mAction,enabledCommands,disabledCommands);}returnNS_OK;}private:RefPtr<nsGlobalWindow>mWindow;nsCOMPtr<nsITabChild>mTabChild;nsStringmAction;};classCommandDispatcher:publicRunnable{public:CommandDispatcher(nsIDOMXULCommandDispatcher*aDispatcher,constnsAString&aAction):mozilla::Runnable("CommandDispatcher"),mDispatcher(aDispatcher),mAction(aAction){}NS_IMETHODRun()override{returnmDispatcher->UpdateCommands(mAction);}nsCOMPtr<nsIDOMXULCommandDispatcher>mDispatcher;nsStringmAction;};nsresultnsGlobalWindow::UpdateCommands(constnsAString&anAction,nsISelection*aSel,int16_taReason){// If this is a child process, redirect to the parent process.if(nsIDocShell*docShell=GetDocShell()){if(nsCOMPtr<nsITabChild>child=docShell->GetTabChild()){nsContentUtils::AddScriptRunner(newChildCommandDispatcher(this,child,anAction));returnNS_OK;}}nsPIDOMWindowOuter*rootWindow=nsGlobalWindow::GetPrivateRoot();if(!rootWindow)returnNS_OK;nsCOMPtr<nsIDOMXULDocument>xulDoc=do_QueryInterface(rootWindow->GetExtantDoc());// See if we contain a XUL document.// selectionchange action is only used for mozbrowser, not for XUL. So we bypass// XUL command dispatch if anAction is "selectionchange".if(xulDoc&&!anAction.EqualsLiteral("selectionchange")){// Retrieve the command dispatcher and call updateCommands on it.nsCOMPtr<nsIDOMXULCommandDispatcher>xulCommandDispatcher;xulDoc->GetCommandDispatcher(getter_AddRefs(xulCommandDispatcher));if(xulCommandDispatcher){nsContentUtils::AddScriptRunner(newCommandDispatcher(xulCommandDispatcher,anAction));}}returnNS_OK;}Selection*nsGlobalWindow::GetSelectionOuter(){MOZ_RELEASE_ASSERT(IsOuterWindow());if(!mDocShell){returnnullptr;}nsCOMPtr<nsIPresShell>presShell=mDocShell->GetPresShell();if(!presShell){returnnullptr;}nsISelection*domSelection=presShell->GetCurrentSelection(SelectionType::eNormal);returndomSelection?domSelection->AsSelection():nullptr;}Selection*nsGlobalWindow::GetSelection(ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(GetSelectionOuter,(),aError,nullptr);}already_AddRefed<nsISelection>nsGlobalWindow::GetSelection(){nsCOMPtr<nsISelection>selection=GetSelectionOuter();returnselection.forget();}boolnsGlobalWindow::FindOuter(constnsAString&aString,boolaCaseSensitive,boolaBackwards,boolaWrapAround,boolaWholeWord,boolaSearchInFrames,boolaShowDialog,ErrorResult&aError){MOZ_RELEASE_ASSERT(IsOuterWindow());Unused<<aShowDialog;if(Preferences::GetBool("dom.disable_window_find",false)){aError.Throw(NS_ERROR_NOT_AVAILABLE);returnfalse;}nsCOMPtr<nsIWebBrowserFind>finder(do_GetInterface(mDocShell));if(!finder){aError.Throw(NS_ERROR_NOT_AVAILABLE);returnfalse;}// Set the options of the searchaError=finder->SetSearchString(PromiseFlatString(aString).get());if(aError.Failed()){returnfalse;}finder->SetMatchCase(aCaseSensitive);finder->SetFindBackwards(aBackwards);finder->SetWrapFind(aWrapAround);finder->SetEntireWord(aWholeWord);finder->SetSearchFrames(aSearchInFrames);// the nsIWebBrowserFind is initialized to use this window// as the search root, but uses focus to set the current search// frame. If we're being called from JS (as here), this window// should be the current search frame.nsCOMPtr<nsIWebBrowserFindInFrames>framesFinder(do_QueryInterface(finder));if(framesFinder){framesFinder->SetRootSearchFrame(AsOuter());// paranoiaframesFinder->SetCurrentSearchFrame(AsOuter());}if(aString.IsEmpty()){returnfalse;}// Launch the search with the passed in search stringbooldidFind=false;aError=finder->FindNext(&didFind);returndidFind;}boolnsGlobalWindow::Find(constnsAString&aString,boolaCaseSensitive,boolaBackwards,boolaWrapAround,boolaWholeWord,boolaSearchInFrames,boolaShowDialog,ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(FindOuter,(aString,aCaseSensitive,aBackwards,aWrapAround,aWholeWord,aSearchInFrames,aShowDialog,aError),aError,false);}voidnsGlobalWindow::GetOrigin(nsAString&aOrigin){MOZ_DIAGNOSTIC_ASSERT(IsInnerWindow());nsContentUtils::GetUTFOrigin(GetPrincipal(),aOrigin);}voidnsGlobalWindow::Atob(constnsAString&aAsciiBase64String,nsAString&aBinaryData,ErrorResult&aError){MOZ_ASSERT(IsInnerWindow());aError=nsContentUtils::Atob(aAsciiBase64String,aBinaryData);}voidnsGlobalWindow::Btoa(constnsAString&aBinaryData,nsAString&aAsciiBase64String,ErrorResult&aError){MOZ_ASSERT(IsInnerWindow());aError=nsContentUtils::Btoa(aBinaryData,aAsciiBase64String);}//*****************************************************************************// nsGlobalWindow::nsIDOMEventTarget//*****************************************************************************nsPIDOMWindowOuter*nsGlobalWindow::GetOwnerGlobalForBindings(){if(IsOuterWindow()){returnAsOuter();}returnnsPIDOMWindowOuter::GetFromCurrentInner(AsInner());}NS_IMETHODIMPnsGlobalWindow::RemoveEventListener(constnsAString&aType,nsIDOMEventListener*aListener,boolaUseCapture){if(RefPtr<EventListenerManager>elm=GetExistingListenerManager()){elm->RemoveEventListener(aType,aListener,aUseCapture);}returnNS_OK;}NS_IMPL_REMOVE_SYSTEM_EVENT_LISTENER(nsGlobalWindow)NS_IMETHODIMPnsGlobalWindow::DispatchEvent(nsIDOMEvent*aEvent,bool*aRetVal){FORWARD_TO_INNER(DispatchEvent,(aEvent,aRetVal),NS_OK);if(!AsInner()->IsCurrentInnerWindow()){NS_WARNING("DispatchEvent called on non-current inner window, dropping. ""Please check the window in the caller instead.");returnNS_ERROR_FAILURE;}if(!mDoc){returnNS_ERROR_FAILURE;}// Obtain a presentation shellnsIPresShell*shell=mDoc->GetShell();RefPtr<nsPresContext>presContext;if(shell){// Retrieve the contextpresContext=shell->GetPresContext();}nsEventStatusstatus=nsEventStatus_eIgnore;nsresultrv=EventDispatcher::DispatchDOMEvent(AsInner(),nullptr,aEvent,presContext,&status);*aRetVal=(status!=nsEventStatus_eConsumeNoDefault);returnrv;}NS_IMETHODIMPnsGlobalWindow::AddEventListener(constnsAString&aType,nsIDOMEventListener*aListener,boolaUseCapture,boolaWantsUntrusted,uint8_taOptionalArgc){NS_ASSERTION(!aWantsUntrusted||aOptionalArgc>1,"Won't check if this is chrome, you want to set ""aWantsUntrusted to false or make the aWantsUntrusted ""explicit by making optional_argc non-zero.");if(!aWantsUntrusted&&(aOptionalArgc<2&&!nsContentUtils::IsChromeDoc(mDoc))){aWantsUntrusted=true;}EventListenerManager*manager=GetOrCreateListenerManager();NS_ENSURE_STATE(manager);manager->AddEventListener(aType,aListener,aUseCapture,aWantsUntrusted);returnNS_OK;}voidnsGlobalWindow::AddEventListener(constnsAString&aType,EventListener*aListener,constAddEventListenerOptionsOrBoolean&aOptions,constNullable<bool>&aWantsUntrusted,ErrorResult&aRv){if(IsOuterWindow()&&mInnerWindow&&!nsContentUtils::CanCallerAccess(mInnerWindow)){aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);return;}boolwantsUntrusted;if(aWantsUntrusted.IsNull()){wantsUntrusted=!nsContentUtils::IsChromeDoc(mDoc);}else{wantsUntrusted=aWantsUntrusted.Value();}EventListenerManager*manager=GetOrCreateListenerManager();if(!manager){aRv.Throw(NS_ERROR_UNEXPECTED);return;}manager->AddEventListener(aType,aListener,aOptions,wantsUntrusted);}NS_IMETHODIMPnsGlobalWindow::AddSystemEventListener(constnsAString&aType,nsIDOMEventListener*aListener,boolaUseCapture,boolaWantsUntrusted,uint8_taOptionalArgc){NS_ASSERTION(!aWantsUntrusted||aOptionalArgc>1,"Won't check if this is chrome, you want to set ""aWantsUntrusted to false or make the aWantsUntrusted ""explicit by making optional_argc non-zero.");if(IsOuterWindow()&&mInnerWindow&&!nsContentUtils::LegacyIsCallerNativeCode()&&!nsContentUtils::CanCallerAccess(mInnerWindow)){returnNS_ERROR_DOM_SECURITY_ERR;}if(!aWantsUntrusted&&(aOptionalArgc<2&&!nsContentUtils::IsChromeDoc(mDoc))){aWantsUntrusted=true;}returnNS_AddSystemEventListener(this,aType,aListener,aUseCapture,aWantsUntrusted);}EventListenerManager*nsGlobalWindow::GetOrCreateListenerManager(){FORWARD_TO_INNER_CREATE(GetOrCreateListenerManager,(),nullptr);if(!mListenerManager){mListenerManager=newEventListenerManager(static_cast<EventTarget*>(this));}returnmListenerManager;}EventListenerManager*nsGlobalWindow::GetExistingListenerManager()const{FORWARD_TO_INNER(GetExistingListenerManager,(),nullptr);returnmListenerManager;}nsIScriptContext*nsGlobalWindow::GetContextForEventHandlers(nsresult*aRv){*aRv=NS_ERROR_UNEXPECTED;NS_ENSURE_TRUE(!IsInnerWindow()||AsInner()->IsCurrentInnerWindow(),nullptr);nsIScriptContext*scx;if((scx=GetContext())){*aRv=NS_OK;returnscx;}returnnullptr;}//*****************************************************************************// nsGlobalWindow::nsPIDOMWindow//*****************************************************************************nsPIDOMWindowOuter*nsGlobalWindow::GetPrivateParent(){MOZ_ASSERT(IsOuterWindow());nsCOMPtr<nsPIDOMWindowOuter>parent=GetParent();if(AsOuter()==parent){nsCOMPtr<nsIContent>chromeElement(do_QueryInterface(mChromeEventHandler));if(!chromeElement)returnnullptr;// This is ok, just means a null parent.nsIDocument*doc=chromeElement->GetComposedDoc();if(!doc)returnnullptr;// This is ok, just means a null parent.returndoc->GetWindow();}returnparent;}nsPIDOMWindowOuter*nsGlobalWindow::GetPrivateRoot(){if(IsInnerWindow()){nsGlobalWindow*outer=GetOuterWindowInternal();if(!outer){NS_WARNING("No outer window available!");returnnullptr;}returnouter->GetPrivateRoot();}nsCOMPtr<nsPIDOMWindowOuter>top=GetTop();nsCOMPtr<nsIContent>chromeElement(do_QueryInterface(mChromeEventHandler));if(chromeElement){nsIDocument*doc=chromeElement->GetComposedDoc();if(doc){nsCOMPtr<nsPIDOMWindowOuter>parent=doc->GetWindow();if(parent){top=parent->GetTop();}}}returntop;}Location*nsGlobalWindow::GetLocation(){// This method can be called on the outer window as well.FORWARD_TO_INNER(GetLocation,(),nullptr);MOZ_RELEASE_ASSERT(IsInnerWindow());if(!mLocation){mLocation=newdom::Location(AsInner(),GetDocShell());}returnmLocation;}voidnsGlobalWindow::ActivateOrDeactivate(boolaActivate){MOZ_ASSERT(IsOuterWindow());if(!mDoc){return;}// Set / unset mIsActive on the top level window, which is used for the// :-moz-window-inactive pseudoclass, and its sheet (if any).nsCOMPtr<nsIWidget>mainWidget=GetMainWidget();nsCOMPtr<nsIWidget>topLevelWidget;if(mainWidget){// Get the top level widget (if the main widget is a sheet, this will// be the sheet's top (non-sheet) parent).topLevelWidget=mainWidget->GetSheetWindowParent();if(!topLevelWidget){topLevelWidget=mainWidget;}}SetActive(aActivate);if(mainWidget!=topLevelWidget){// This is a workaround for the following problem:// When a window with an open sheet gains or loses focus, only the sheet// window receives the NS_ACTIVATE/NS_DEACTIVATE event. However the// styling of the containing top level window also needs to change. We// get around this by calling nsPIDOMWindow::SetActive() on both windows.// Get the top level widget's nsGlobalWindownsCOMPtr<nsPIDOMWindowOuter>topLevelWindow;// widgetListener should be a nsXULWindownsIWidgetListener*listener=topLevelWidget->GetWidgetListener();if(listener){nsCOMPtr<nsIXULWindow>window=listener->GetXULWindow();nsCOMPtr<nsIInterfaceRequestor>req(do_QueryInterface(window));topLevelWindow=do_GetInterface(req);}if(topLevelWindow){topLevelWindow->SetActive(aActivate);}}}staticboolNotifyDocumentTree(nsIDocument*aDocument,void*aData){aDocument->EnumerateSubDocuments(NotifyDocumentTree,nullptr);aDocument->DocumentStatesChanged(NS_DOCUMENT_STATE_WINDOW_INACTIVE);returntrue;}voidnsGlobalWindow::SetActive(boolaActive){nsPIDOMWindow::SetActive(aActive);if(mDoc){NotifyDocumentTree(mDoc,nullptr);}}boolnsGlobalWindow::IsTopLevelWindowActive(){nsCOMPtr<nsIDocShellTreeItem>treeItem(GetDocShell());if(!treeItem){returnfalse;}nsCOMPtr<nsIDocShellTreeItem>rootItem;treeItem->GetRootTreeItem(getter_AddRefs(rootItem));if(!rootItem){returnfalse;}nsCOMPtr<nsPIDOMWindowOuter>domWindow=rootItem->GetWindow();returndomWindow&&domWindow->IsActive();}voidnsGlobalWindow::SetIsBackground(boolaIsBackground){MOZ_ASSERT(IsOuterWindow());boolchanged=aIsBackground!=AsOuter()->IsBackground();SetIsBackgroundInternal(aIsBackground);nsGlobalWindow*inner=GetCurrentInnerWindowInternal();if(inner&&changed){inner->mTimeoutManager->UpdateBackgroundState();}if(aIsBackground){// Notify gamepadManager we are at the background window,// we need to stop vibrate.if(inner){inner->StopGamepadHaptics();}return;}if(inner){inner->SyncGamepadState();}}voidnsGlobalWindow::SetIsBackgroundInternal(boolaIsBackground){if(mIsBackground!=aIsBackground){TabGroup()->WindowChangedBackgroundStatus(aIsBackground);}mIsBackground=aIsBackground;}voidnsGlobalWindow::MaybeUpdateTouchState(){FORWARD_TO_INNER_VOID(MaybeUpdateTouchState,());if(mMayHaveTouchEventListener){nsCOMPtr<nsIObserverService>observerService=services::GetObserverService();if(observerService){observerService->NotifyObservers(static_cast<nsIDOMWindow*>(this),DOM_TOUCH_LISTENER_ADDED,nullptr);}}}voidnsGlobalWindow::EnableGamepadUpdates(){MOZ_ASSERT(IsInnerWindow());if(mHasGamepad){RefPtr<GamepadManager>gamepadManager(GamepadManager::GetService());if(gamepadManager){gamepadManager->AddListener(this);}}}voidnsGlobalWindow::DisableGamepadUpdates(){MOZ_ASSERT(IsInnerWindow());if(mHasGamepad){RefPtr<GamepadManager>gamepadManager(GamepadManager::GetService());if(gamepadManager){gamepadManager->RemoveListener(this);}}}voidnsGlobalWindow::EnableVRUpdates(){MOZ_ASSERT(IsInnerWindow());if(mHasVREvents&&!mVREventObserver){mVREventObserver=newVREventObserver(this);}}voidnsGlobalWindow::DisableVRUpdates(){MOZ_ASSERT(IsInnerWindow());if(mVREventObserver){mVREventObserver->DisconnectFromOwner();mVREventObserver=nullptr;}}voidnsGlobalWindow::SetChromeEventHandler(EventTarget*aChromeEventHandler){MOZ_ASSERT(IsOuterWindow());SetChromeEventHandlerInternal(aChromeEventHandler);// update the chrome event handler on all our inner windowsfor(nsGlobalWindow*inner=(nsGlobalWindow*)PR_LIST_HEAD(this);inner!=this;inner=(nsGlobalWindow*)PR_NEXT_LINK(inner)){NS_ASSERTION(!inner->mOuterWindow||inner->mOuterWindow==AsOuter(),"bad outer window pointer");inner->SetChromeEventHandlerInternal(aChromeEventHandler);}}staticboolIsLink(nsIContent*aContent){returnaContent&&(aContent->IsHTMLElement(nsGkAtoms::a)||aContent->AttrValueIs(kNameSpaceID_XLink,nsGkAtoms::type,nsGkAtoms::simple,eCaseMatters));}staticboolShouldShowFocusRingIfFocusedByMouse(nsIContent*aNode){if(!aNode){returntrue;}return!IsLink(aNode)&&!aNode->IsAnyOfHTMLElements(nsGkAtoms::video,nsGkAtoms::audio);}voidnsGlobalWindow::SetFocusedNode(nsIContent*aNode,uint32_taFocusMethod,boolaNeedsFocus){FORWARD_TO_INNER_VOID(SetFocusedNode,(aNode,aFocusMethod,aNeedsFocus));if(aNode&&aNode->GetComposedDoc()!=mDoc){NS_WARNING("Trying to set focus to a node from a wrong document");return;}if(mCleanedUp){NS_ASSERTION(!aNode,"Trying to focus cleaned up window!");aNode=nullptr;aNeedsFocus=false;}if(mFocusedNode!=aNode){UpdateCanvasFocus(false,aNode);mFocusedNode=aNode;mFocusMethod=aFocusMethod&FOCUSMETHOD_MASK;mShowFocusRingForContent=false;}if(mFocusedNode){// if a node was focused by a keypress, turn on focus rings for the// window.if(mFocusMethod&nsIFocusManager::FLAG_BYKEY){mFocusByKeyOccurred=true;}elseif(// otherwise, we set mShowFocusRingForContent, as we don't want this to// be permanent for the window. On Windows, focus rings are only shown// when the FLAG_SHOWRING flag is used. On other platforms, focus rings// are only visible on some elements.#ifndef XP_WIN!(mFocusMethod&nsIFocusManager::FLAG_BYMOUSE)||ShouldShowFocusRingIfFocusedByMouse(aNode)||#endifaFocusMethod&nsIFocusManager::FLAG_SHOWRING){mShowFocusRingForContent=true;}}if(aNeedsFocus)mNeedsFocus=aNeedsFocus;}uint32_tnsGlobalWindow::GetFocusMethod(){FORWARD_TO_INNER(GetFocusMethod,(),0);returnmFocusMethod;}boolnsGlobalWindow::ShouldShowFocusRing(){FORWARD_TO_INNER(ShouldShowFocusRing,(),false);if(mShowFocusRingForContent||mFocusByKeyOccurred){returntrue;}nsCOMPtr<nsPIWindowRoot>root=GetTopWindowRoot();returnroot?root->ShowFocusRings():false;}voidnsGlobalWindow::SetKeyboardIndicators(UIStateChangeTypeaShowAccelerators,UIStateChangeTypeaShowFocusRings){MOZ_ASSERT(IsOuterWindow());nsPIDOMWindowOuter*piWin=GetPrivateRoot();if(!piWin){return;}MOZ_ASSERT(piWin==AsOuter());boololdShouldShowFocusRing=ShouldShowFocusRing();// only change the flags that have been modifiednsCOMPtr<nsPIWindowRoot>windowRoot=do_QueryInterface(mChromeEventHandler);if(!windowRoot){return;}if(aShowAccelerators!=UIStateChangeType_NoChange){windowRoot->SetShowAccelerators(aShowAccelerators==UIStateChangeType_Set);}if(aShowFocusRings!=UIStateChangeType_NoChange){windowRoot->SetShowFocusRings(aShowFocusRings==UIStateChangeType_Set);}nsContentUtils::SetKeyboardIndicatorsOnRemoteChildren(GetOuterWindow(),aShowAccelerators,aShowFocusRings);boolnewShouldShowFocusRing=ShouldShowFocusRing();if(mHasFocus&&mFocusedNode&&oldShouldShowFocusRing!=newShouldShowFocusRing&&mFocusedNode->IsElement()){// Update mFocusedNode's state.if(newShouldShowFocusRing){mFocusedNode->AsElement()->AddStates(NS_EVENT_STATE_FOCUSRING);}else{mFocusedNode->AsElement()->RemoveStates(NS_EVENT_STATE_FOCUSRING);}}}boolnsGlobalWindow::TakeFocus(boolaFocus,uint32_taFocusMethod){FORWARD_TO_INNER(TakeFocus,(aFocus,aFocusMethod),false);if(mCleanedUp){returnfalse;}if(aFocus)mFocusMethod=aFocusMethod&FOCUSMETHOD_MASK;if(mHasFocus!=aFocus){mHasFocus=aFocus;UpdateCanvasFocus(true,mFocusedNode);}// if mNeedsFocus is true, then the document has not yet received a// document-level focus event. If there is a root content node, then return// true to tell the calling focus manager that a focus event is expected. If// there is no root content node, the document hasn't loaded enough yet, or// there isn't one and there is no point in firing a focus event.if(aFocus&&mNeedsFocus&&mDoc&&mDoc->GetRootElement()!=nullptr){mNeedsFocus=false;returntrue;}mNeedsFocus=false;returnfalse;}voidnsGlobalWindow::SetReadyForFocus(){FORWARD_TO_INNER_VOID(SetReadyForFocus,());boololdNeedsFocus=mNeedsFocus;mNeedsFocus=false;nsIFocusManager*fm=nsFocusManager::GetFocusManager();if(fm){fm->WindowShown(GetOuterWindow(),oldNeedsFocus);}}voidnsGlobalWindow::PageHidden(){FORWARD_TO_INNER_VOID(PageHidden,());// the window is being hidden, so tell the focus manager that the frame is// no longer valid. Use the persisted field to determine if the document// is being destroyed.nsIFocusManager*fm=nsFocusManager::GetFocusManager();if(fm){fm->WindowHidden(GetOuterWindow());}mNeedsFocus=true;}classHashchangeCallback:publicRunnable{public:HashchangeCallback(constnsAString&aOldURL,constnsAString&aNewURL,nsGlobalWindow*aWindow):mozilla::Runnable("HashchangeCallback"),mWindow(aWindow){MOZ_ASSERT(mWindow);MOZ_ASSERT(mWindow->IsInnerWindow());mOldURL.Assign(aOldURL);mNewURL.Assign(aNewURL);}NS_IMETHODRun()override{NS_PRECONDITION(NS_IsMainThread(),"Should be called on the main thread.");returnmWindow->FireHashchange(mOldURL,mNewURL);}private:nsStringmOldURL;nsStringmNewURL;RefPtr<nsGlobalWindow>mWindow;};nsresultnsGlobalWindow::DispatchAsyncHashchange(nsIURI*aOldURI,nsIURI*aNewURI){MOZ_RELEASE_ASSERT(IsInnerWindow());// Make sure that aOldURI and aNewURI are identical up to the '#', and that// their hashes are different.boolequal=false;NS_ENSURE_STATE(NS_SUCCEEDED(aOldURI->EqualsExceptRef(aNewURI,&equal))&&equal);nsAutoCStringoldHash,newHash;boololdHasHash,newHasHash;NS_ENSURE_STATE(NS_SUCCEEDED(aOldURI->GetRef(oldHash))&&NS_SUCCEEDED(aNewURI->GetRef(newHash))&&NS_SUCCEEDED(aOldURI->GetHasRef(&oldHasHash))&&NS_SUCCEEDED(aNewURI->GetHasRef(&newHasHash))&&(oldHasHash!=newHasHash||!oldHash.Equals(newHash)));nsAutoCStringoldSpec,newSpec;nsresultrv=aOldURI->GetSpec(oldSpec);NS_ENSURE_SUCCESS(rv,rv);rv=aNewURI->GetSpec(newSpec);NS_ENSURE_SUCCESS(rv,rv);NS_ConvertUTF8toUTF16oldWideSpec(oldSpec);NS_ConvertUTF8toUTF16newWideSpec(newSpec);nsCOMPtr<nsIRunnable>callback=newHashchangeCallback(oldWideSpec,newWideSpec,this);returnDispatch("HashchangeCallback",TaskCategory::Other,callback.forget());}nsresultnsGlobalWindow::FireHashchange(constnsAString&aOldURL,constnsAString&aNewURL){MOZ_ASSERT(IsInnerWindow());// Don't do anything if the window is frozen.if(IsFrozen()){returnNS_OK;}// Get a presentation shell for use in creating the hashchange event.NS_ENSURE_STATE(AsInner()->IsCurrentInnerWindow());nsIPresShell*shell=mDoc->GetShell();RefPtr<nsPresContext>presContext;if(shell){presContext=shell->GetPresContext();}HashChangeEventInitinit;init.mBubbles=true;init.mCancelable=false;init.mNewURL=aNewURL;init.mOldURL=aOldURL;RefPtr<HashChangeEvent>event=HashChangeEvent::Constructor(this,NS_LITERAL_STRING("hashchange"),init);event->SetTrusted(true);booldummy;returnDispatchEvent(event,&dummy);}nsresultnsGlobalWindow::DispatchSyncPopState(){MOZ_RELEASE_ASSERT(IsInnerWindow());NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),"Must be safe to run script here.");nsresultrv=NS_OK;// Bail if the window is frozen.if(IsFrozen()){returnNS_OK;}// Get the document's pending state object -- it contains the data we're// going to send along with the popstate event. The object is serialized// using structured clone.nsCOMPtr<nsIVariant>stateObj;rv=mDoc->GetStateObject(getter_AddRefs(stateObj));NS_ENSURE_SUCCESS(rv,rv);// Obtain a presentation shell for use in creating a popstate event.nsIPresShell*shell=mDoc->GetShell();RefPtr<nsPresContext>presContext;if(shell){presContext=shell->GetPresContext();}boolresult=true;AutoJSAPIjsapi;result=jsapi.Init(AsInner());NS_ENSURE_TRUE(result,NS_ERROR_FAILURE);JSContext*cx=jsapi.cx();JS::Rooted<JS::Value>stateJSValue(cx,JS::NullValue());result=stateObj?VariantToJsval(cx,stateObj,&stateJSValue):true;NS_ENSURE_TRUE(result,NS_ERROR_FAILURE);RootedDictionary<PopStateEventInit>init(cx);init.mBubbles=true;init.mCancelable=false;init.mState=stateJSValue;RefPtr<PopStateEvent>event=PopStateEvent::Constructor(this,NS_LITERAL_STRING("popstate"),init);event->SetTrusted(true);event->SetTarget(this);booldummy;// default actionreturnDispatchEvent(event,&dummy);}// Find an nsICanvasFrame under aFrame. Only search the principal// child lists. aFrame must be non-null.staticnsCanvasFrame*FindCanvasFrame(nsIFrame*aFrame){nsCanvasFrame*canvasFrame=do_QueryFrame(aFrame);if(canvasFrame){returncanvasFrame;}for(nsIFrame*kid:aFrame->PrincipalChildList()){canvasFrame=FindCanvasFrame(kid);if(canvasFrame){returncanvasFrame;}}returnnullptr;}//-------------------------------------------------------// Tells the HTMLFrame/CanvasFrame that is now has focusvoidnsGlobalWindow::UpdateCanvasFocus(boolaFocusChanged,nsIContent*aNewContent){MOZ_ASSERT(IsInnerWindow());// this is called from the inner window so use GetDocShellnsIDocShell*docShell=GetDocShell();if(!docShell)return;booleditable;docShell->GetEditable(&editable);if(editable)return;nsCOMPtr<nsIPresShell>presShell=docShell->GetPresShell();if(!presShell||!mDoc)return;Element*rootElement=mDoc->GetRootElement();if(rootElement){if((mHasFocus||aFocusChanged)&&(mFocusedNode==rootElement||aNewContent==rootElement)){nsIFrame*frame=rootElement->GetPrimaryFrame();if(frame){frame=frame->GetParent();nsCanvasFrame*canvasFrame=do_QueryFrame(frame);if(canvasFrame){canvasFrame->SetHasFocus(mHasFocus&&rootElement==aNewContent);}}}}else{// Look for the frame the hard waynsIFrame*frame=presShell->GetRootFrame();if(frame){nsCanvasFrame*canvasFrame=FindCanvasFrame(frame);if(canvasFrame){canvasFrame->SetHasFocus(false);}}}}already_AddRefed<nsICSSDeclaration>nsGlobalWindow::GetComputedStyle(Element&aElt,constnsAString&aPseudoElt,ErrorResult&aError){MOZ_ASSERT(IsInnerWindow());returnGetComputedStyleHelper(aElt,aPseudoElt,false,aError);}already_AddRefed<nsICSSDeclaration>nsGlobalWindow::GetDefaultComputedStyle(Element&aElt,constnsAString&aPseudoElt,ErrorResult&aError){MOZ_ASSERT(IsInnerWindow());returnGetComputedStyleHelper(aElt,aPseudoElt,true,aError);}nsresultnsGlobalWindow::GetComputedStyleHelper(nsIDOMElement*aElt,constnsAString&aPseudoElt,boolaDefaultStylesOnly,nsIDOMCSSStyleDeclaration**aReturn){MOZ_ASSERT(IsInnerWindow());NS_ENSURE_ARG_POINTER(aReturn);*aReturn=nullptr;nsCOMPtr<dom::Element>element=do_QueryInterface(aElt);if(!element){returnNS_ERROR_DOM_NOT_SUPPORTED_ERR;}ErrorResultrv;nsCOMPtr<nsIDOMCSSStyleDeclaration>declaration=GetComputedStyleHelper(*element,aPseudoElt,aDefaultStylesOnly,rv);declaration.forget(aReturn);returnrv.StealNSResult();}already_AddRefed<nsICSSDeclaration>nsGlobalWindow::GetComputedStyleHelperOuter(Element&aElt,constnsAString&aPseudoElt,boolaDefaultStylesOnly){MOZ_RELEASE_ASSERT(IsOuterWindow());if(!mDocShell){returnnullptr;}nsCOMPtr<nsIPresShell>presShell=mDocShell->GetPresShell();if(!presShell){// Try flushing frames on our parent in case there's a pending// style change that will create the presshell.auto*parent=nsGlobalWindow::Cast(GetPrivateParent());if(!parent){returnnullptr;}parent->FlushPendingNotifications(FlushType::Frames);// Might have killed mDocShellif(!mDocShell){returnnullptr;}presShell=mDocShell->GetPresShell();if(!presShell){returnnullptr;}}RefPtr<nsComputedDOMStyle>compStyle=NS_NewComputedDOMStyle(&aElt,aPseudoElt,presShell,aDefaultStylesOnly?nsComputedDOMStyle::eDefaultOnly:nsComputedDOMStyle::eAll);returncompStyle.forget();}already_AddRefed<nsICSSDeclaration>nsGlobalWindow::GetComputedStyleHelper(Element&aElt,constnsAString&aPseudoElt,boolaDefaultStylesOnly,ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(GetComputedStyleHelperOuter,(aElt,aPseudoElt,aDefaultStylesOnly),aError,nullptr);}Storage*nsGlobalWindow::GetSessionStorage(ErrorResult&aError){MOZ_RELEASE_ASSERT(IsInnerWindow());nsIPrincipal*principal=GetPrincipal();nsIDocShell*docShell=GetDocShell();if(!principal||!docShell||!Preferences::GetBool(kStorageEnabled)){returnnullptr;}if(mSessionStorage){MOZ_LOG(gDOMLeakPRLog,LogLevel::Debug,("nsGlobalWindow %p has %p sessionStorage",this,mSessionStorage.get()));boolcanAccess=principal->Subsumes(mSessionStorage->Principal());NS_ASSERTION(canAccess,"This window owned sessionStorage ""that could not be accessed!");if(!canAccess){mSessionStorage=nullptr;}}if(!mSessionStorage){nsStringdocumentURI;if(mDoc){aError=mDoc->GetDocumentURI(documentURI);if(NS_WARN_IF(aError.Failed())){returnnullptr;}}// If the document has the sandboxed origin flag set// don't allow access to sessionStorage.if(!mDoc){aError.Throw(NS_ERROR_FAILURE);returnnullptr;}if(mDoc->GetSandboxFlags()&SANDBOXED_ORIGIN){aError.Throw(NS_ERROR_DOM_SECURITY_ERR);returnnullptr;}nsresultrv;nsCOMPtr<nsIDOMStorageManager>storageManager=do_QueryInterface(docShell,&rv);if(NS_FAILED(rv)){aError.Throw(rv);returnnullptr;}nsCOMPtr<nsIDOMStorage>storage;aError=storageManager->CreateStorage(AsInner(),principal,documentURI,IsPrivateBrowsing(),getter_AddRefs(storage));if(aError.Failed()){returnnullptr;}mSessionStorage=static_cast<Storage*>(storage.get());MOZ_ASSERT(mSessionStorage);MOZ_LOG(gDOMLeakPRLog,LogLevel::Debug,("nsGlobalWindow %p tried to get a new sessionStorage %p",this,mSessionStorage.get()));if(!mSessionStorage){aError.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);returnnullptr;}}MOZ_LOG(gDOMLeakPRLog,LogLevel::Debug,("nsGlobalWindow %p returns %p sessionStorage",this,mSessionStorage.get()));returnmSessionStorage;}Storage*nsGlobalWindow::GetLocalStorage(ErrorResult&aError){MOZ_RELEASE_ASSERT(IsInnerWindow());if(!Preferences::GetBool(kStorageEnabled)){returnnullptr;}if(!mLocalStorage){if(nsContentUtils::StorageAllowedForWindow(AsInner())==nsContentUtils::StorageAccess::eDeny){aError.Throw(NS_ERROR_DOM_SECURITY_ERR);returnnullptr;}nsIPrincipal*principal=GetPrincipal();if(!principal){returnnullptr;}nsresultrv;nsCOMPtr<nsIDOMStorageManager>storageManager=do_GetService("@mozilla.org/dom/localStorage-manager;1",&rv);if(NS_FAILED(rv)){aError.Throw(rv);returnnullptr;}nsStringdocumentURI;if(mDoc){aError=mDoc->GetDocumentURI(documentURI);if(NS_WARN_IF(aError.Failed())){returnnullptr;}}nsCOMPtr<nsIDOMStorage>storage;aError=storageManager->CreateStorage(AsInner(),principal,documentURI,IsPrivateBrowsing(),getter_AddRefs(storage));if(aError.Failed()){returnnullptr;}mLocalStorage=static_cast<Storage*>(storage.get());MOZ_ASSERT(mLocalStorage);}returnmLocalStorage;}IDBFactory*nsGlobalWindow::GetIndexedDB(ErrorResult&aError){MOZ_RELEASE_ASSERT(IsInnerWindow());if(!mIndexedDB){// This may keep mIndexedDB null without setting an error.aError=IDBFactory::CreateForWindow(AsInner(),getter_AddRefs(mIndexedDB));}returnmIndexedDB;}//*****************************************************************************// nsGlobalWindow::nsIInterfaceRequestor//*****************************************************************************NS_IMETHODIMPnsGlobalWindow::GetInterface(constnsIID&aIID,void**aSink){NS_ENSURE_ARG_POINTER(aSink);*aSink=nullptr;if(aIID.Equals(NS_GET_IID(nsIDocCharset))){nsGlobalWindow*outer=GetOuterWindowInternal();NS_ENSURE_TRUE(outer,NS_ERROR_NOT_INITIALIZED);NS_WARNING("Using deprecated nsIDocCharset: use nsIDocShell.GetCharset() instead ");nsCOMPtr<nsIDocCharset>docCharset(do_QueryInterface(outer->mDocShell));docCharset.forget(aSink);}elseif(aIID.Equals(NS_GET_IID(nsIWebNavigation))){nsGlobalWindow*outer=GetOuterWindowInternal();NS_ENSURE_TRUE(outer,NS_ERROR_NOT_INITIALIZED);nsCOMPtr<nsIWebNavigation>webNav(do_QueryInterface(outer->mDocShell));webNav.forget(aSink);}elseif(aIID.Equals(NS_GET_IID(nsIDocShell))){nsGlobalWindow*outer=GetOuterWindowInternal();NS_ENSURE_TRUE(outer,NS_ERROR_NOT_INITIALIZED);nsCOMPtr<nsIDocShell>docShell=outer->mDocShell;docShell.forget(aSink);}#ifdef NS_PRINTINGelseif(aIID.Equals(NS_GET_IID(nsIWebBrowserPrint))){nsGlobalWindow*outer=GetOuterWindowInternal();NS_ENSURE_TRUE(outer,NS_ERROR_NOT_INITIALIZED);if(outer->mDocShell){nsCOMPtr<nsIContentViewer>viewer;outer->mDocShell->GetContentViewer(getter_AddRefs(viewer));if(viewer){nsCOMPtr<nsIWebBrowserPrint>webBrowserPrint(do_QueryInterface(viewer));webBrowserPrint.forget(aSink);}}}#endifelseif(aIID.Equals(NS_GET_IID(nsIDOMWindowUtils))){nsGlobalWindow*outer=GetOuterWindowInternal();NS_ENSURE_TRUE(outer,NS_ERROR_NOT_INITIALIZED);if(!mWindowUtils){mWindowUtils=newnsDOMWindowUtils(outer);}*aSink=mWindowUtils;NS_ADDREF(((nsISupports*)*aSink));}elseif(aIID.Equals(NS_GET_IID(nsILoadContext))){nsGlobalWindow*outer=GetOuterWindowInternal();NS_ENSURE_TRUE(outer,NS_ERROR_NOT_INITIALIZED);nsCOMPtr<nsILoadContext>loadContext(do_QueryInterface(outer->mDocShell));loadContext.forget(aSink);}else{returnQueryInterface(aIID,aSink);}return*aSink?NS_OK:NS_ERROR_NO_INTERFACE;}voidnsGlobalWindow::GetInterface(JSContext*aCx,nsIJSID*aIID,JS::MutableHandle<JS::Value>aRetval,ErrorResult&aError){MOZ_ASSERT(IsInnerWindow());dom::GetInterface(aCx,this,aIID,aRetval,aError);}already_AddRefed<CacheStorage>nsGlobalWindow::GetCaches(ErrorResult&aRv){MOZ_ASSERT(IsInnerWindow());if(!mCacheStorage){boolforceTrustedOrigin=GetOuterWindow()->GetServiceWorkersTestingEnabled();nsContentUtils::StorageAccessaccess=nsContentUtils::StorageAllowedForWindow(AsInner());// We don't block the cache API when being told to only allow storage for the// current session.boolstorageBlocked=access<=nsContentUtils::StorageAccess::ePrivateBrowsing;mCacheStorage=CacheStorage::CreateOnMainThread(cache::DEFAULT_NAMESPACE,this,GetPrincipal(),storageBlocked,forceTrustedOrigin,aRv);}RefPtr<CacheStorage>ref=mCacheStorage;returnref.forget();}already_AddRefed<ServiceWorkerRegistration>nsPIDOMWindowInner::GetServiceWorkerRegistration(constnsAString&aScope){RefPtr<ServiceWorkerRegistration>registration;if(!mServiceWorkerRegistrationTable.Get(aScope,getter_AddRefs(registration))){registration=ServiceWorkerRegistration::CreateForMainThread(this,aScope);mServiceWorkerRegistrationTable.Put(aScope,registration);}returnregistration.forget();}voidnsPIDOMWindowInner::InvalidateServiceWorkerRegistration(constnsAString&aScope){mServiceWorkerRegistrationTable.Remove(aScope);}voidnsGlobalWindow::FireOfflineStatusEventIfChanged(){if(!AsInner()->IsCurrentInnerWindow())return;// Don't fire an event if the status hasn't changedif(mWasOffline==NS_IsOffline()){return;}mWasOffline=!mWasOffline;nsAutoStringname;if(mWasOffline){name.AssignLiteral("offline");}else{name.AssignLiteral("online");}// The event is fired at the body element, or if there is no body element,// at the document.nsCOMPtr<EventTarget>eventTarget=mDoc.get();nsHTMLDocument*htmlDoc=mDoc->AsHTMLDocument();if(htmlDoc){Element*body=htmlDoc->GetBody();if(body){eventTarget=body;}}else{Element*documentElement=mDoc->GetDocumentElement();if(documentElement){eventTarget=documentElement;}}nsContentUtils::DispatchTrustedEvent(mDoc,eventTarget,name,true,false);}classNotifyIdleObserverRunnable:publicRunnable{public:NotifyIdleObserverRunnable(nsIIdleObserver*aIdleObserver,uint32_taTimeInS,boolaCallOnidle,nsGlobalWindow*aIdleWindow):mozilla::Runnable("NotifyIdleObserverRunnable"),mIdleObserver(aIdleObserver),mTimeInS(aTimeInS),mIdleWindow(aIdleWindow),mCallOnidle(aCallOnidle){}NS_IMETHODRun()override{if(mIdleWindow->ContainsIdleObserver(mIdleObserver,mTimeInS)){returnmCallOnidle?mIdleObserver->Onidle():mIdleObserver->Onactive();}returnNS_OK;}private:nsCOMPtr<nsIIdleObserver>mIdleObserver;uint32_tmTimeInS;RefPtr<nsGlobalWindow>mIdleWindow;// If false then call on activeboolmCallOnidle;};voidnsGlobalWindow::NotifyIdleObserver(IdleObserverHolder*aIdleObserverHolder,boolaCallOnidle){MOZ_ASSERT(aIdleObserverHolder);aIdleObserverHolder->mPrevNotificationIdle=aCallOnidle;nsCOMPtr<nsIRunnable>caller=newNotifyIdleObserverRunnable(aIdleObserverHolder->mIdleObserver,aIdleObserverHolder->mTimeInS,aCallOnidle,this);if(NS_FAILED(Dispatch("NotifyIdleObserverRunnable",TaskCategory::Other,caller.forget()))){NS_WARNING("Failed to dispatch thread for idle observer notification.");}}boolnsGlobalWindow::ContainsIdleObserver(nsIIdleObserver*aIdleObserver,uint32_taTimeInS){MOZ_ASSERT(aIdleObserver,"Idle observer not instantiated.");boolfound=false;nsTObserverArray<IdleObserverHolder>::ForwardIteratoriter(mIdleObservers);while(iter.HasMore()){IdleObserverHolder&idleObserver=iter.GetNext();if(idleObserver.mIdleObserver==aIdleObserver&&idleObserver.mTimeInS==aTimeInS){found=true;break;}}returnfound;}voidIdleActiveTimerCallback(nsITimer*aTimer,void*aClosure){RefPtr<nsGlobalWindow>idleWindow=static_cast<nsGlobalWindow*>(aClosure);MOZ_ASSERT(idleWindow,"Idle window has not been instantiated.");idleWindow->HandleIdleActiveEvent();}voidIdleObserverTimerCallback(nsITimer*aTimer,void*aClosure){RefPtr<nsGlobalWindow>idleWindow=static_cast<nsGlobalWindow*>(aClosure);MOZ_ASSERT(idleWindow,"Idle window has not been instantiated.");idleWindow->HandleIdleObserverCallback();}voidnsGlobalWindow::HandleIdleObserverCallback(){MOZ_ASSERT(IsInnerWindow(),"Must be an inner window!");MOZ_ASSERT(static_cast<uint32_t>(mIdleCallbackIndex)<mIdleObservers.Length(),"Idle callback index exceeds array bounds!");IdleObserverHolder&idleObserver=mIdleObservers.ElementAt(mIdleCallbackIndex);NotifyIdleObserver(&idleObserver,true);mIdleCallbackIndex++;if(NS_FAILED(ScheduleNextIdleObserverCallback())){NS_WARNING("Failed to set next idle observer callback.");}}nsresultnsGlobalWindow::ScheduleNextIdleObserverCallback(){MOZ_ASSERT(IsInnerWindow(),"Must be an inner window!");MOZ_ASSERT(mIdleService,"No idle service!");if(mIdleCallbackIndex<0||static_cast<uint32_t>(mIdleCallbackIndex)>=mIdleObservers.Length()){returnNS_OK;}IdleObserverHolder&idleObserver=mIdleObservers.ElementAt(mIdleCallbackIndex);uint32_tuserIdleTimeMS=0;nsresultrv=mIdleService->GetIdleTime(&userIdleTimeMS);NS_ENSURE_SUCCESS(rv,rv);uint32_tcallbackTimeMS=0;if(idleObserver.mTimeInS*1000+mIdleFuzzFactor>userIdleTimeMS){callbackTimeMS=idleObserver.mTimeInS*1000-userIdleTimeMS+mIdleFuzzFactor;}mIdleTimer->Cancel();rv=mIdleTimer->InitWithNamedFuncCallback(IdleObserverTimerCallback,this,callbackTimeMS,nsITimer::TYPE_ONE_SHOT,"nsGlobalWindow::ScheduleNextIdleObserverCallback");NS_ENSURE_SUCCESS(rv,rv);returnNS_OK;}uint32_tnsGlobalWindow::GetFuzzTimeMS(){MOZ_ASSERT(IsInnerWindow(),"Must be an inner window!");if(sIdleObserversAPIFuzzTimeDisabled){return0;}uint32_trandNum=MAX_IDLE_FUZZ_TIME_MS;size_tnbytes=PR_GetRandomNoise(&randNum,sizeof(randNum));if(nbytes!=sizeof(randNum)){NS_WARNING("PR_GetRandomNoise(...) Not implemented or no available noise!");returnMAX_IDLE_FUZZ_TIME_MS;}if(randNum>MAX_IDLE_FUZZ_TIME_MS){randNum%=MAX_IDLE_FUZZ_TIME_MS;}returnrandNum;}nsresultnsGlobalWindow::ScheduleActiveTimerCallback(){MOZ_ASSERT(IsInnerWindow(),"Must be an inner window!");if(!mAddActiveEventFuzzTime){returnHandleIdleActiveEvent();}MOZ_ASSERT(mIdleTimer);mIdleTimer->Cancel();uint32_tfuzzFactorInMS=GetFuzzTimeMS();nsresultrv=mIdleTimer->InitWithNamedFuncCallback(IdleActiveTimerCallback,this,fuzzFactorInMS,nsITimer::TYPE_ONE_SHOT,"nsGlobalWindow::ScheduleActiveTimerCallback");NS_ENSURE_SUCCESS(rv,rv);returnNS_OK;}nsresultnsGlobalWindow::HandleIdleActiveEvent(){MOZ_ASSERT(IsInnerWindow(),"Must be an inner window!");if(mCurrentlyIdle){mIdleCallbackIndex=0;mIdleFuzzFactor=GetFuzzTimeMS();nsresultrv=ScheduleNextIdleObserverCallback();NS_ENSURE_SUCCESS(rv,rv);returnNS_OK;}mIdleCallbackIndex=-1;MOZ_ASSERT(mIdleTimer);mIdleTimer->Cancel();nsTObserverArray<IdleObserverHolder>::ForwardIteratoriter(mIdleObservers);while(iter.HasMore()){IdleObserverHolder&idleObserver=iter.GetNext();if(idleObserver.mPrevNotificationIdle){NotifyIdleObserver(&idleObserver,false);}}returnNS_OK;}nsGlobalWindow::SlowScriptResponsensGlobalWindow::ShowSlowScriptDialog(){MOZ_ASSERT(IsInnerWindow());nsresultrv;AutoJSContextcx;if(Preferences::GetBool("dom.always_stop_slow_scripts")){returnKillSlowScript;}// If it isn't safe to run script, then it isn't safe to bring up the prompt// (since that spins the event loop). In that (rare) case, we just kill the// script and report a warning.if(!nsContentUtils::IsSafeToRunScript()){JS_ReportWarningASCII(cx,"A long running script was terminated");returnKillSlowScript;}// If our document is not active, just kill the script: we've been unloadedif(!AsInner()->HasActiveDocument()){returnKillSlowScript;}// Check if we should offer the option to debugJS::AutoFilenamefilename;unsignedlineno;// Computing the line number can be very expensive (see bug 1330231 for// example), and we don't use the line number anywhere except than in the// parent process, so we avoid computing it elsewhere. This gives us most of// the wins we are interested in, since the source of the slowness here is// minified scripts which is more common in Web content that is loaded in the// content process.unsigned*linenop=XRE_IsParentProcess()?&lineno:nullptr;boolhasFrame=JS::DescribeScriptedCaller(cx,&filename,linenop);// Record the slow script event if we haven't done so already for this inner window// (which represents a particular page to the user).if(!mHasHadSlowScript){Telemetry::Accumulate(Telemetry::SLOW_SCRIPT_PAGE_COUNT,1);}mHasHadSlowScript=true;if(XRE_IsContentProcess()&&ProcessHangMonitor::Get()){ProcessHangMonitor::SlowScriptActionaction;RefPtr<ProcessHangMonitor>monitor=ProcessHangMonitor::Get();nsIDocShell*docShell=GetDocShell();nsCOMPtr<nsITabChild>child=docShell?docShell->GetTabChild():nullptr;action=monitor->NotifySlowScript(child,filename.get());if(action==ProcessHangMonitor::Terminate){returnKillSlowScript;}if(action==ProcessHangMonitor::StartDebugger){// Spin a nested event loop so that the debugger in the parent can fetch// any information it needs. Once the debugger has started, return to the// script.RefPtr<nsGlobalWindow>outer=GetOuterWindowInternal();outer->EnterModalState();SpinEventLoopUntil([&](){returnmonitor->IsDebuggerStartupComplete();});outer->LeaveModalState();returnContinueSlowScript;}returnContinueSlowScriptAndKeepNotifying;}// Reached only on non-e10s - once per slow script dialog.// On e10s - we probe once at ProcessHangsMonitor.jsmTelemetry::Accumulate(Telemetry::SLOW_SCRIPT_NOTICE_COUNT,1);// Get the nsIPrompt interface from the docshellnsCOMPtr<nsIDocShell>ds=GetDocShell();NS_ENSURE_TRUE(ds,KillSlowScript);nsCOMPtr<nsIPrompt>prompt=do_GetInterface(ds);NS_ENSURE_TRUE(prompt,KillSlowScript);// Prioritize the SlowScriptDebug interface over JSD1.nsCOMPtr<nsISlowScriptDebugCallback>debugCallback;if(hasFrame){constchar*debugCID="@mozilla.org/dom/slow-script-debug;1";nsCOMPtr<nsISlowScriptDebug>debugService=do_GetService(debugCID,&rv);if(NS_SUCCEEDED(rv)){debugService->GetActivationHandler(getter_AddRefs(debugCallback));}}boolshowDebugButton=!!debugCallback;// Get localizable stringsnsXPIDLStringtitle,msg,stopButton,waitButton,debugButton,neverShowDlg;rv=nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,"KillScriptTitle",title);nsresulttmp=nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,"StopScriptButton",stopButton);if(NS_FAILED(tmp)){rv=tmp;}tmp=nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,"WaitForScriptButton",waitButton);if(NS_FAILED(tmp)){rv=tmp;}tmp=nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,"DontAskAgain",neverShowDlg);if(NS_FAILED(tmp)){rv=tmp;}if(showDebugButton){tmp=nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,"DebugScriptButton",debugButton);if(NS_FAILED(tmp)){rv=tmp;}tmp=nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,"KillScriptWithDebugMessage",msg);if(NS_FAILED(tmp)){rv=tmp;}}else{tmp=nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,"KillScriptMessage",msg);if(NS_FAILED(tmp)){rv=tmp;}}// GetStringFromName can return NS_OK and still give nullptr stringif(NS_FAILED(rv)||!title||!msg||!stopButton||!waitButton||(!debugButton&&showDebugButton)||!neverShowDlg){NS_ERROR("Failed to get localized strings.");returnContinueSlowScript;}// Append file and line number information, if availableif(filename.get()){nsXPIDLStringscriptLocation;// We want to drop the middle part of too-long locations. We'll// define "too-long" as longer than 60 UTF-16 code units. Just// have to be a bit careful about unpaired surrogates.NS_ConvertUTF8toUTF16filenameUTF16(filename.get());if(filenameUTF16.Length()>60){// XXXbz Do we need to insert any bidi overrides here?size_tcutStart=30;size_tcutLength=filenameUTF16.Length()-60;MOZ_ASSERT(cutLength>0);if(NS_IS_LOW_SURROGATE(filenameUTF16[cutStart])){// Don't truncate before the low surrogate, in case it's preceded by a// high surrogate and forms a single Unicode character. Instead, just// include the low surrogate.++cutStart;--cutLength;}if(NS_IS_LOW_SURROGATE(filenameUTF16[cutStart+cutLength])){// Likewise, don't drop a trailing low surrogate here. We want to// increase cutLength, since it might be 0 already so we can't very well// decrease it.++cutLength;}// Insert U+2026 HORIZONTAL ELLIPSISfilenameUTF16.Replace(cutStart,cutLength,NS_LITERAL_STRING(u"\x2026"));}constchar16_t*formatParams[]={filenameUTF16.get()};rv=nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,"KillScriptLocation",formatParams,scriptLocation);if(NS_SUCCEEDED(rv)&&scriptLocation){msg.AppendLiteral("\n\n");msg.Append(scriptLocation);msg.Append(':');msg.AppendInt(lineno);}}int32_tbuttonPressed=0;// In case the user exits dialog by clicking X.boolneverShowDlgChk=false;uint32_tbuttonFlags=nsIPrompt::BUTTON_POS_1_DEFAULT+(nsIPrompt::BUTTON_TITLE_IS_STRING*(nsIPrompt::BUTTON_POS_0+nsIPrompt::BUTTON_POS_1));// Add a third button if necessary.if(showDebugButton)buttonFlags+=nsIPrompt::BUTTON_TITLE_IS_STRING*nsIPrompt::BUTTON_POS_2;// Null out the operation callback while we're re-entering JS here.boolold=JS_DisableInterruptCallback(cx);// Open the dialog.rv=prompt->ConfirmEx(title,msg,buttonFlags,waitButton,stopButton,debugButton,neverShowDlg,&neverShowDlgChk,&buttonPressed);JS_ResetInterruptCallback(cx,old);if(NS_SUCCEEDED(rv)&&(buttonPressed==0)){returnneverShowDlgChk?AlwaysContinueSlowScript:ContinueSlowScript;}if(buttonPressed==2){if(debugCallback){rv=debugCallback->HandleSlowScriptDebug(this);returnNS_SUCCEEDED(rv)?ContinueSlowScript:KillSlowScript;}}JS_ClearPendingException(cx);returnKillSlowScript;}uint32_tnsGlobalWindow::FindInsertionIndex(IdleObserverHolder*aIdleObserver){MOZ_ASSERT(IsInnerWindow());MOZ_ASSERT(aIdleObserver,"Idle observer not instantiated.");uint32_ti=0;nsTObserverArray<IdleObserverHolder>::ForwardIteratoriter(mIdleObservers);while(iter.HasMore()){IdleObserverHolder&idleObserver=iter.GetNext();if(idleObserver.mTimeInS>aIdleObserver->mTimeInS){break;}i++;MOZ_ASSERT(i<=mIdleObservers.Length(),"Array index out of bounds error.");}returni;}nsresultnsGlobalWindow::RegisterIdleObserver(nsIIdleObserver*aIdleObserver){MOZ_ASSERT(IsInnerWindow(),"Must be an inner window!");nsresultrv;if(mIdleObservers.IsEmpty()){mIdleService=do_GetService("@mozilla.org/widget/idleservice;1",&rv);NS_ENSURE_SUCCESS(rv,rv);rv=mIdleService->AddIdleObserver(mObserver,MIN_IDLE_NOTIFICATION_TIME_S);NS_ENSURE_SUCCESS(rv,rv);if(!mIdleTimer){mIdleTimer=do_CreateInstance(NS_TIMER_CONTRACTID,&rv);NS_ENSURE_SUCCESS(rv,rv);}else{mIdleTimer->Cancel();}}MOZ_ASSERT(mIdleService);MOZ_ASSERT(mIdleTimer);IdleObserverHoldertmpIdleObserver;tmpIdleObserver.mIdleObserver=aIdleObserver;rv=aIdleObserver->GetTime(&tmpIdleObserver.mTimeInS);NS_ENSURE_SUCCESS(rv,rv);NS_ENSURE_ARG_MAX(tmpIdleObserver.mTimeInS,UINT32_MAX/1000);NS_ENSURE_ARG_MIN(tmpIdleObserver.mTimeInS,MIN_IDLE_NOTIFICATION_TIME_S);uint32_tinsertAtIndex=FindInsertionIndex(&tmpIdleObserver);if(insertAtIndex==mIdleObservers.Length()){mIdleObservers.AppendElement(tmpIdleObserver);}else{mIdleObservers.InsertElementAt(insertAtIndex,tmpIdleObserver);}booluserIsIdle=false;rv=nsContentUtils::IsUserIdle(MIN_IDLE_NOTIFICATION_TIME_S,&userIsIdle);NS_ENSURE_SUCCESS(rv,rv);// Special case. First idle observer added to empty list while the user is idle.// Haven't received 'idle' topic notification from slow idle service yet.// Need to wait for the idle notification and then notify idle observers in the list.if(userIsIdle&&mIdleCallbackIndex==-1){returnNS_OK;}if(!mCurrentlyIdle){returnNS_OK;}MOZ_ASSERT(mIdleCallbackIndex>=0);if(static_cast<int32_t>(insertAtIndex)<mIdleCallbackIndex){IdleObserverHolder&idleObserver=mIdleObservers.ElementAt(insertAtIndex);NotifyIdleObserver(&idleObserver,true);mIdleCallbackIndex++;returnNS_OK;}if(static_cast<int32_t>(insertAtIndex)==mIdleCallbackIndex){mIdleTimer->Cancel();rv=ScheduleNextIdleObserverCallback();NS_ENSURE_SUCCESS(rv,rv);}returnNS_OK;}nsresultnsGlobalWindow::FindIndexOfElementToRemove(nsIIdleObserver*aIdleObserver,int32_t*aRemoveElementIndex){MOZ_ASSERT(IsInnerWindow(),"Must be an inner window!");MOZ_ASSERT(aIdleObserver,"Idle observer not instantiated.");*aRemoveElementIndex=0;if(mIdleObservers.IsEmpty()){returnNS_ERROR_FAILURE;}uint32_taIdleObserverTimeInS;nsresultrv=aIdleObserver->GetTime(&aIdleObserverTimeInS);NS_ENSURE_SUCCESS(rv,rv);NS_ENSURE_ARG_MIN(aIdleObserverTimeInS,MIN_IDLE_NOTIFICATION_TIME_S);nsTObserverArray<IdleObserverHolder>::ForwardIteratoriter(mIdleObservers);while(iter.HasMore()){IdleObserverHolder&idleObserver=iter.GetNext();if(idleObserver.mTimeInS==aIdleObserverTimeInS&&idleObserver.mIdleObserver==aIdleObserver){break;}(*aRemoveElementIndex)++;}returnstatic_cast<uint32_t>(*aRemoveElementIndex)>=mIdleObservers.Length()?NS_ERROR_FAILURE:NS_OK;}nsresultnsGlobalWindow::UnregisterIdleObserver(nsIIdleObserver*aIdleObserver){MOZ_ASSERT(IsInnerWindow(),"Must be an inner window!");int32_tremoveElementIndex;nsresultrv=FindIndexOfElementToRemove(aIdleObserver,&removeElementIndex);if(NS_FAILED(rv)){NS_WARNING("Idle observer not found in list of idle observers. No idle observer removed.");returnNS_OK;}mIdleObservers.RemoveElementAt(removeElementIndex);MOZ_ASSERT(mIdleTimer);if(mIdleObservers.IsEmpty()&&mIdleService){rv=mIdleService->RemoveIdleObserver(mObserver,MIN_IDLE_NOTIFICATION_TIME_S);NS_ENSURE_SUCCESS(rv,rv);mIdleService=nullptr;mIdleTimer->Cancel();mIdleCallbackIndex=-1;returnNS_OK;}if(!mCurrentlyIdle){returnNS_OK;}if(removeElementIndex<mIdleCallbackIndex){mIdleCallbackIndex--;returnNS_OK;}if(removeElementIndex!=mIdleCallbackIndex){returnNS_OK;}mIdleTimer->Cancel();// If the last element in the array had been notified then decrement// mIdleCallbackIndex because an idle was removed from the list of// idle observers.// Example: add idle observer with time 1, 2, 3,// Idle notifications for idle observers with time 1, 2, 3 are complete// Remove idle observer with time 3 while the user is still idle.// The user never transitioned to active state.// Add an idle observer with idle time 4if(static_cast<uint32_t>(mIdleCallbackIndex)==mIdleObservers.Length()){mIdleCallbackIndex--;}rv=ScheduleNextIdleObserverCallback();NS_ENSURE_SUCCESS(rv,rv);returnNS_OK;}nsresultnsGlobalWindow::Observe(nsISupports*aSubject,constchar*aTopic,constchar16_t*aData){if(!nsCRT::strcmp(aTopic,NS_IOSERVICE_OFFLINE_STATUS_TOPIC)){if(!IsFrozen()){// Fires an offline status event if the offline status has changedFireOfflineStatusEventIfChanged();}returnNS_OK;}if(!nsCRT::strcmp(aTopic,OBSERVER_TOPIC_IDLE)){mCurrentlyIdle=true;if(IsFrozen()){// need to fire only one idle event while the window is frozen.mNotifyIdleObserversIdleOnThaw=true;mNotifyIdleObserversActiveOnThaw=false;}elseif(AsInner()->IsCurrentInnerWindow()){HandleIdleActiveEvent();}returnNS_OK;}if(!nsCRT::strcmp(aTopic,OBSERVER_TOPIC_ACTIVE)){mCurrentlyIdle=false;if(IsFrozen()){mNotifyIdleObserversActiveOnThaw=true;mNotifyIdleObserversIdleOnThaw=false;}elseif(AsInner()->IsCurrentInnerWindow()){MOZ_ASSERT(IsInnerWindow());ScheduleActiveTimerCallback();}returnNS_OK;}// We need these for our private-browsing check below; so save them off.// (And we can't do the private-browsing enforcement check as part of our// outer conditional because otherwise we'll trigger an NS_WARNING if control// flow reaches the bottom of this method.)boolisNonPrivateLocalStorageChange=!nsCRT::strcmp(aTopic,"dom-storage2-changed");boolisPrivateLocalStorageChange=!nsCRT::strcmp(aTopic,"dom-private-storage2-changed");if(isNonPrivateLocalStorageChange||isPrivateLocalStorageChange){// Enforce that the source storage area's private browsing state matches// this window's state. These flag checks and their maintenance independent// from the principal's OriginAttributes matter because chrome docshells// that are part of private browsing windows can be private browsing without// having their OriginAttributes set (because they have the system// principal).boolisPrivateBrowsing=IsPrivateBrowsing();if((isNonPrivateLocalStorageChange&&isPrivateBrowsing)||(isPrivateLocalStorageChange&&!isPrivateBrowsing)){returnNS_OK;}// We require that aData be either u"SessionStorage" or u"localStorage".// Assert under debug, but ignore the bogus event under non-debug.MOZ_ASSERT(aData);if(!aData){returnNS_ERROR_INVALID_ARG;}// LocalStorage can only exist on an inner window, and we don't want to// generate events on frozen or otherwise-navigated-away from windows.// (Actually, this code used to try and buffer events for frozen windows,// but it never worked, so we've removed it. See bug 1285898.)if(!IsInnerWindow()||!AsInner()->IsCurrentInnerWindow()||IsFrozen()){returnNS_OK;}nsIPrincipal*principal=GetPrincipal();if(!principal){returnNS_OK;}RefPtr<StorageEvent>event=static_cast<StorageEvent*>(aSubject);if(!event){returnNS_ERROR_FAILURE;}boolfireMozStorageChanged=false;nsAutoStringeventType;eventType.AssignLiteral("storage");if(!NS_strcmp(aData,u"sessionStorage")){nsCOMPtr<nsIDOMStorage>changingStorage=event->GetStorageArea();MOZ_ASSERT(changingStorage);boolcheck=false;nsCOMPtr<nsIDOMStorageManager>storageManager=do_QueryInterface(GetDocShell());if(storageManager){nsresultrv=storageManager->CheckStorage(principal,changingStorage,&check);if(NS_FAILED(rv)){returnrv;}}if(!check){// This storage event is not coming from our storage or is coming// from a different docshell, i.e. it is a clone, ignore this event.returnNS_OK;}MOZ_LOG(gDOMLeakPRLog,LogLevel::Debug,("nsGlobalWindow %p with sessionStorage %p passing event from %p",this,mSessionStorage.get(),changingStorage.get()));fireMozStorageChanged=mSessionStorage==changingStorage;if(fireMozStorageChanged){eventType.AssignLiteral("MozSessionStorageChanged");}}else{MOZ_ASSERT(!NS_strcmp(aData,u"localStorage"));nsIPrincipal*storagePrincipal=event->GetPrincipal();if(!storagePrincipal){returnNS_OK;}boolequals=false;nsresultrv=storagePrincipal->Equals(principal,&equals);NS_ENSURE_SUCCESS(rv,rv);if(!equals){returnNS_OK;}fireMozStorageChanged=mLocalStorage==event->GetStorageArea();if(fireMozStorageChanged){eventType.AssignLiteral("MozLocalStorageChanged");}}// Clone the storage event included in the observer notification. We want// to dispatch clones rather than the original event.ErrorResulterror;RefPtr<StorageEvent>clonedEvent=CloneStorageEvent(eventType,event,error);if(error.Failed()){returnerror.StealNSResult();}clonedEvent->SetTrusted(true);if(fireMozStorageChanged){WidgetEvent*internalEvent=clonedEvent->WidgetEventPtr();internalEvent->mFlags.mOnlyChromeDispatch=true;}booldefaultActionEnabled;DispatchEvent(clonedEvent,&defaultActionEnabled);returnNS_OK;}if(!nsCRT::strcmp(aTopic,"offline-cache-update-added")){if(mApplicationCache)returnNS_OK;// Instantiate the application object now. It observes update belonging to// this window's document and correctly updates the applicationCache object// state.nsCOMPtr<nsIDOMOfflineResourceList>applicationCache=GetApplicationCache();nsCOMPtr<nsIObserver>observer=do_QueryInterface(applicationCache);if(observer)observer->Observe(aSubject,aTopic,aData);returnNS_OK;}#ifdef MOZ_B2Gif(!nsCRT::strcmp(aTopic,NS_NETWORK_ACTIVITY_BLIP_UPLOAD_TOPIC)||!nsCRT::strcmp(aTopic,NS_NETWORK_ACTIVITY_BLIP_DOWNLOAD_TOPIC)){MOZ_ASSERT(IsInnerWindow());if(!AsInner()->IsCurrentInnerWindow()){returnNS_OK;}RefPtr<Event>event=NS_NewDOMEvent(this,nullptr,nullptr);event->InitEvent(!nsCRT::strcmp(aTopic,NS_NETWORK_ACTIVITY_BLIP_UPLOAD_TOPIC)?NETWORK_UPLOAD_EVENT_NAME:NETWORK_DOWNLOAD_EVENT_NAME,false,false);event->SetTrusted(true);booldummy;returnDispatchEvent(event,&dummy);}#endif // MOZ_B2Gif(!nsCRT::strcmp(aTopic,NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)){MOZ_ASSERT(!NS_strcmp(aData,u"intl.accept_languages"));MOZ_ASSERT(IsInnerWindow());// The user preferred languages have changed, we need to fire an event on// Window object and invalidate the cache for navigator.languages. It is// done for every change which can be a waste of cycles but those should be// fairly rare.// We MUST invalidate navigator.languages before sending the event in the// very likely situation where an event handler will try to read its value.if(mNavigator){NavigatorBinding::ClearCachedLanguageValue(mNavigator);NavigatorBinding::ClearCachedLanguagesValue(mNavigator);}// The event has to be dispatched only to the current inner window.if(!AsInner()->IsCurrentInnerWindow()){returnNS_OK;}RefPtr<Event>event=NS_NewDOMEvent(this,nullptr,nullptr);event->InitEvent(NS_LITERAL_STRING("languagechange"),false,false);event->SetTrusted(true);booldummy;returnDispatchEvent(event,&dummy);}NS_WARNING("unrecognized topic in nsGlobalWindow::Observe");returnNS_ERROR_FAILURE;}already_AddRefed<StorageEvent>nsGlobalWindow::CloneStorageEvent(constnsAString&aType,constRefPtr<StorageEvent>&aEvent,ErrorResult&aRv){MOZ_ASSERT(IsInnerWindow());StorageEventInitdict;dict.mBubbles=aEvent->Bubbles();dict.mCancelable=aEvent->Cancelable();aEvent->GetKey(dict.mKey);aEvent->GetOldValue(dict.mOldValue);aEvent->GetNewValue(dict.mNewValue);aEvent->GetUrl(dict.mUrl);RefPtr<Storage>storageArea=aEvent->GetStorageArea();RefPtr<Storage>storage;// If null, this is a localStorage event received by IPC.if(!storageArea){storage=GetLocalStorage(aRv);if(aRv.Failed()||!storage){returnnullptr;}MOZ_ASSERT(storage->Type()==Storage::eLocalStorage);RefPtr<LocalStorage>localStorage=static_cast<LocalStorage*>(storage.get());// We must apply the current change to the 'local' localStorage.localStorage->ApplyEvent(aEvent);}elseif(storageArea->Type()==Storage::eSessionStorage){storage=GetSessionStorage(aRv);}else{MOZ_ASSERT(storageArea->Type()==Storage::eLocalStorage);storage=GetLocalStorage(aRv);}if(aRv.Failed()||!storage){returnnullptr;}MOZ_ASSERT(storage);MOZ_ASSERT_IF(storageArea,storage->IsForkOf(storageArea));dict.mStorageArea=storage;RefPtr<StorageEvent>event=StorageEvent::Constructor(this,aType,dict);returnevent.forget();}voidnsGlobalWindow::Suspend(){MOZ_ASSERT(NS_IsMainThread());MOZ_DIAGNOSTIC_ASSERT(IsInnerWindow());// We can only safely suspend windows that are the current inner window. If// its not the current inner, then we are in one of two different cases.// Either we are in the bfcache or we are doomed window that is going away.// When a window becomes inactive we purposely avoid placing already suspended// windows into the bfcache. It only expects windows suspended due to the// Freeze() method which occurs while the window is still the current inner.// So we must not call Suspend() on bfcache windows at this point or this// invariant will be broken. If the window is doomed there is no point in// suspending it since it will soon be gone.if(!AsInner()->IsCurrentInnerWindow()){return;}// All children are also suspended. This ensure mSuspendDepth is// set properly and the timers are properly canceled for each child.CallOnChildren(&nsGlobalWindow::Suspend);mSuspendDepth+=1;if(mSuspendDepth!=1){return;}nsCOMPtr<nsIDeviceSensors>ac=do_GetService(NS_DEVICE_SENSORS_CONTRACTID);if(ac){for(uint32_ti=0;i<mEnabledSensors.Length();i++)ac->RemoveWindowListener(mEnabledSensors[i],this);}DisableGamepadUpdates();DisableVRUpdates();mozilla::dom::workers::SuspendWorkersForWindow(AsInner());SuspendIdleRequests();mTimeoutManager->Suspend();// Suspend all of the AudioContexts for this windowfor(uint32_ti=0;i<mAudioContexts.Length();++i){ErrorResultdummy;RefPtr<Promise>d=mAudioContexts[i]->Suspend(dummy);}}voidnsGlobalWindow::Resume(){MOZ_ASSERT(NS_IsMainThread());MOZ_DIAGNOSTIC_ASSERT(IsInnerWindow());// We can only safely resume a window if its the current inner window. If// its not the current inner, then we are in one of two different cases.// Either we are in the bfcache or we are doomed window that is going away.// If a window is suspended when it becomes inactive we purposely do not// put it in the bfcache, so Resume should never be needed in that case.// If the window is doomed then there is no point in resuming it.if(!AsInner()->IsCurrentInnerWindow()){return;}// Resume all children. This restores timers recursively canceled// in Suspend() and ensures all children have the correct mSuspendDepth.CallOnChildren(&nsGlobalWindow::Resume);MOZ_ASSERT(mSuspendDepth!=0);mSuspendDepth-=1;if(mSuspendDepth!=0){return;}// We should not be able to resume a frozen window. It must be Thaw()'d first.MOZ_ASSERT(mFreezeDepth==0);nsCOMPtr<nsIDeviceSensors>ac=do_GetService(NS_DEVICE_SENSORS_CONTRACTID);if(ac){for(uint32_ti=0;i<mEnabledSensors.Length();i++)ac->AddWindowListener(mEnabledSensors[i],this);}EnableGamepadUpdates();EnableVRUpdates();// Resume all of the AudioContexts for this windowfor(uint32_ti=0;i<mAudioContexts.Length();++i){ErrorResultdummy;RefPtr<Promise>d=mAudioContexts[i]->Resume(dummy);}mTimeoutManager->Resume();ResumeIdleRequests();// Resume all of the workers for this window. We must do this// after timeouts since workers may have queued events that can trigger// a setTimeout().mozilla::dom::workers::ResumeWorkersForWindow(AsInner());}boolnsGlobalWindow::IsSuspended()const{MOZ_ASSERT(NS_IsMainThread());// No inner means we are effectively suspendedif(IsOuterWindow()){if(!mInnerWindow){returntrue;}returnmInnerWindow->IsSuspended();}returnmSuspendDepth!=0;}voidnsGlobalWindow::Freeze(){MOZ_ASSERT(NS_IsMainThread());Suspend();FreezeInternal();}voidnsGlobalWindow::FreezeInternal(){MOZ_ASSERT(NS_IsMainThread());MOZ_DIAGNOSTIC_ASSERT(IsInnerWindow());MOZ_DIAGNOSTIC_ASSERT(AsInner()->IsCurrentInnerWindow());MOZ_DIAGNOSTIC_ASSERT(IsSuspended());CallOnChildren(&nsGlobalWindow::FreezeInternal);mFreezeDepth+=1;MOZ_ASSERT(mSuspendDepth>=mFreezeDepth);if(mFreezeDepth!=1){return;}mozilla::dom::workers::FreezeWorkersForWindow(AsInner());mTimeoutManager->Freeze();NotifyDOMWindowFrozen(this);}voidnsGlobalWindow::Thaw(){MOZ_ASSERT(NS_IsMainThread());ThawInternal();Resume();}voidnsGlobalWindow::ThawInternal(){MOZ_ASSERT(NS_IsMainThread());MOZ_DIAGNOSTIC_ASSERT(IsInnerWindow());MOZ_DIAGNOSTIC_ASSERT(AsInner()->IsCurrentInnerWindow());MOZ_DIAGNOSTIC_ASSERT(IsSuspended());CallOnChildren(&nsGlobalWindow::ThawInternal);MOZ_ASSERT(mFreezeDepth!=0);mFreezeDepth-=1;MOZ_ASSERT(mSuspendDepth>=mFreezeDepth);if(mFreezeDepth!=0){return;}mTimeoutManager->Thaw();mozilla::dom::workers::ThawWorkersForWindow(AsInner());NotifyDOMWindowThawed(this);}boolnsGlobalWindow::IsFrozen()const{MOZ_ASSERT(NS_IsMainThread());// No inner means we are effectively frozenif(IsOuterWindow()){if(!mInnerWindow){returntrue;}returnmInnerWindow->IsFrozen();}boolfrozen=mFreezeDepth!=0;MOZ_ASSERT_IF(frozen,IsSuspended());returnfrozen;}voidnsGlobalWindow::SyncStateFromParentWindow(){// This method should only be called on an inner window that has been// assigned to an outer window already.MOZ_ASSERT(IsInnerWindow());MOZ_ASSERT(AsInner()->IsCurrentInnerWindow());nsPIDOMWindowOuter*outer=GetOuterWindow();MOZ_ASSERT(outer);// Attempt to find our parent windows.nsCOMPtr<Element>frame=outer->GetFrameElementInternal();nsPIDOMWindowOuter*parentOuter=frame?frame->OwnerDoc()->GetWindow():nullptr;nsGlobalWindow*parentInner=parentOuter?nsGlobalWindow::Cast(parentOuter->GetCurrentInnerWindow()):nullptr;// If our outer is in a modal state, but our parent is not in a modal// state, then we must apply the suspend directly. If our parent is// in a modal state then we should get the suspend automatically// via the parentSuspendDepth application below.if((!parentInner||!parentInner->IsInModalState())&&IsInModalState()){Suspend();}uint32_tparentFreezeDepth=parentInner?parentInner->mFreezeDepth:0;uint32_tparentSuspendDepth=parentInner?parentInner->mSuspendDepth:0;// Since every Freeze() calls Suspend(), the suspend count must// be equal or greater to the freeze count.MOZ_ASSERT(parentFreezeDepth<=parentSuspendDepth);// First apply the Freeze() calls.for(uint32_ti=0;i<parentFreezeDepth;++i){Freeze();}// Now apply only the number of Suspend() calls to reach the target// suspend count after applying the Freeze() calls.for(uint32_ti=0;i<(parentSuspendDepth-parentFreezeDepth);++i){Suspend();}}template<typenameMethod>voidnsGlobalWindow::CallOnChildren(MethodaMethod){MOZ_ASSERT(NS_IsMainThread());MOZ_ASSERT(IsInnerWindow());MOZ_ASSERT(AsInner()->IsCurrentInnerWindow());nsCOMPtr<nsIDocShell>docShell=GetDocShell();if(!docShell){return;}int32_tchildCount=0;docShell->GetChildCount(&childCount);for(int32_ti=0;i<childCount;++i){nsCOMPtr<nsIDocShellTreeItem>childShell;docShell->GetChildAt(i,getter_AddRefs(childShell));NS_ASSERTION(childShell,"null child shell");nsCOMPtr<nsPIDOMWindowOuter>pWin=childShell->GetWindow();if(!pWin){continue;}auto*win=nsGlobalWindow::Cast(pWin);nsGlobalWindow*inner=win->GetCurrentInnerWindowInternal();// This is a bit hackish. Only freeze/suspend windows which are truly our// subwindows.nsCOMPtr<Element>frame=pWin->GetFrameElementInternal();if(!mDoc||!frame||mDoc!=frame->OwnerDoc()||!inner){continue;}(inner->*aMethod)();}}nsresultnsGlobalWindow::FireDelayedDOMEvents(){FORWARD_TO_INNER(FireDelayedDOMEvents,(),NS_ERROR_UNEXPECTED);if(mApplicationCache){static_cast<nsDOMOfflineResourceList*>(mApplicationCache.get())->FirePendingEvents();}// Fires an offline status event if the offline status has changedFireOfflineStatusEventIfChanged();if(mNotifyIdleObserversIdleOnThaw){mNotifyIdleObserversIdleOnThaw=false;HandleIdleActiveEvent();}if(mNotifyIdleObserversActiveOnThaw){mNotifyIdleObserversActiveOnThaw=false;ScheduleActiveTimerCallback();}nsCOMPtr<nsIDocShell>docShell=GetDocShell();if(docShell){int32_tchildCount=0;docShell->GetChildCount(&childCount);for(int32_ti=0;i<childCount;++i){nsCOMPtr<nsIDocShellTreeItem>childShell;docShell->GetChildAt(i,getter_AddRefs(childShell));NS_ASSERTION(childShell,"null child shell");if(nsCOMPtr<nsPIDOMWindowOuter>pWin=childShell->GetWindow()){auto*win=nsGlobalWindow::Cast(pWin);win->FireDelayedDOMEvents();}}}returnNS_OK;}//*****************************************************************************// nsGlobalWindow: Window Control Functions//*****************************************************************************nsPIDOMWindowOuter*nsGlobalWindow::GetParentInternal(){if(IsInnerWindow()){nsGlobalWindow*outer=GetOuterWindowInternal();if(!outer){NS_WARNING("No outer window available!");returnnullptr;}returnouter->GetParentInternal();}nsCOMPtr<nsPIDOMWindowOuter>parent=GetParent();if(parent&&parent!=AsOuter()){returnparent;}returnnullptr;}voidnsGlobalWindow::UnblockScriptedClosing(){MOZ_ASSERT(IsOuterWindow());mBlockScriptedClosingFlag=false;}classAutoUnblockScriptClosing{private:RefPtr<nsGlobalWindow>mWin;public:explicitAutoUnblockScriptClosing(nsGlobalWindow*aWin):mWin(aWin){MOZ_ASSERT(mWin);MOZ_ASSERT(mWin->IsOuterWindow());}~AutoUnblockScriptClosing(){void(nsGlobalWindow::*run)()=&nsGlobalWindow::UnblockScriptedClosing;nsCOMPtr<nsIRunnable>caller=NewRunnableMethod("AutoUnblockScriptClosing::~AutoUnblockScriptClosing",mWin,run);mWin->Dispatch("nsGlobalWindow::UnblockScriptedClosing",TaskCategory::Other,caller.forget());}};nsresultnsGlobalWindow::OpenInternal(constnsAString&aUrl,constnsAString&aName,constnsAString&aOptions,boolaDialog,boolaContentModal,boolaCalledNoScript,boolaDoJSFixups,boolaNavigate,nsIArray*argv,nsISupports*aExtraArgument,nsIDocShellLoadInfo*aLoadInfo,boolaForceNoOpener,nsPIDOMWindowOuter**aReturn){MOZ_ASSERT(IsOuterWindow());#ifdef DEBUGuint32_targc=0;if(argv)argv->GetLength(&argc);#endifNS_PRECONDITION(!aExtraArgument||(!argv&&argc==0),"Can't pass in arguments both ways");NS_PRECONDITION(!aCalledNoScript||(!argv&&argc==0),"Can't pass JS args when called via the noscript methods");mozilla::Maybe<AutoUnblockScriptClosing>closeUnblocker;// Calls to window.open from script should navigate.MOZ_ASSERT(aCalledNoScript||aNavigate);*aReturn=nullptr;nsCOMPtr<nsIWebBrowserChrome>chrome=GetWebBrowserChrome();if(!chrome){// No chrome means we don't want to go through with this open call// -- see nsIWindowWatcher.idlreturnNS_ERROR_NOT_AVAILABLE;}NS_ASSERTION(mDocShell,"Must have docshell here");boolforceNoOpener=aForceNoOpener;if(!forceNoOpener){// Unlike other window flags, "noopener" comes from splitting on commas with// HTML whitespace trimming...nsCharSeparatedTokenizerTemplate<nsContentUtils::IsHTMLWhitespace>tok(aOptions,',');while(tok.hasMoreTokens()){if(tok.nextToken().EqualsLiteral("noopener")){forceNoOpener=true;break;}}}// XXXbz When this gets fixed to not use LegacyIsCallerNativeCode()// (indirectly) maybe we can nix the AutoJSAPI usage OnLinkClickEvent::Run.// But note that if you change this to GetEntryGlobal(), say, then// OnLinkClickEvent::Run will need a full-blown AutoEntryScript.constboolcheckForPopup=!nsContentUtils::LegacyIsCallerChromeOrNativeCode()&&!aDialog&&!WindowExists(aName,forceNoOpener,!aCalledNoScript);// Note: it's very important that this be an nsXPIDLCString, since we want// .get() on it to return nullptr until we write stuff to it. The window// watcher expects a null URL string if there is no URL to load.nsXPIDLCStringurl;nsresultrv=NS_OK;// It's important to do this security check before determining whether this// window opening should be blocked, to ensure that we don't FireAbuseEvents// for a window opening that wouldn't have succeeded in the first place.if(!aUrl.IsEmpty()){AppendUTF16toUTF8(aUrl,url);// It's safe to skip the security check below if we're not a dialog// because window.openDialog is not callable from content script. See bug// 56851.//// If we're not navigating, we assume that whoever *does* navigate the// window will do a security check of their own.if(url.get()&&!aDialog&&aNavigate)rv=SecurityCheckURL(url.get());}if(NS_FAILED(rv))returnrv;PopupControlStateabuseLevel=gPopupControlState;if(checkForPopup){abuseLevel=RevisePopupAbuseLevel(abuseLevel);if(abuseLevel>=openAbused){if(!aCalledNoScript){// If script in some other window is doing a window.open on us and// it's being blocked, then it's OK to close us afterwards, probably.// But if we're doing a window.open on ourselves and block the popup,// prevent this window from closing until after this script terminates// so that whatever popup blocker UI the app has will be visible.nsCOMPtr<nsPIDOMWindowInner>entryWindow=do_QueryInterface(GetEntryGlobal());// Note that entryWindow can be null here if some JS component was the// place where script was entered for this JS execution.if(entryWindow&&entryWindow->GetOuterWindow()==this->AsOuter()){mBlockScriptedClosingFlag=true;closeUnblocker.emplace(this);}}FireAbuseEvents(aUrl,aName,aOptions);returnaDoJSFixups?NS_OK:NS_ERROR_FAILURE;}}nsCOMPtr<mozIDOMWindowProxy>domReturn;nsCOMPtr<nsIWindowWatcher>wwatch=do_GetService(NS_WINDOWWATCHER_CONTRACTID,&rv);NS_ENSURE_TRUE(wwatch,rv);NS_ConvertUTF16toUTF8options(aOptions);NS_ConvertUTF16toUTF8name(aName);constchar*options_ptr=aOptions.IsEmpty()?nullptr:options.get();constchar*name_ptr=aName.IsEmpty()?nullptr:name.get();nsCOMPtr<nsPIWindowWatcher>pwwatch(do_QueryInterface(wwatch));NS_ENSURE_STATE(pwwatch);MOZ_ASSERT_IF(checkForPopup,abuseLevel<openAbused);// At this point we should know for a fact that if checkForPopup then// abuseLevel < openAbused, so we could just check for abuseLevel ==// openControlled. But let's be defensive just in case and treat anything// that fails the above assert as a spam popup too, if it ever happens.boolisPopupSpamWindow=checkForPopup&&(abuseLevel>=openControlled);{// Reset popup state while opening a window to prevent the// current state from being active the whole time a modal// dialog is open.nsAutoPopupStatePusherpopupStatePusher(openAbused,true);if(!aCalledNoScript){// We asserted at the top of this function that aNavigate is true for// !aCalledNoScript.rv=pwwatch->OpenWindow2(AsOuter(),url.get(),name_ptr,options_ptr,/* aCalledFromScript = */true,aDialog,aNavigate,argv,isPopupSpamWindow,forceNoOpener,aLoadInfo,getter_AddRefs(domReturn));}else{// Force a system caller here so that the window watcher won't screw us// up. We do NOT want this case looking at the JS context on the stack// when searching. Compare comments on// nsIDOMWindow::OpenWindow and nsIWindowWatcher::OpenWindow.// Note: Because nsWindowWatcher is so broken, it's actually important// that we don't force a system caller here, because that screws it up// when it tries to compute the caller principal to associate with dialog// arguments. That whole setup just really needs to be rewritten. :-(Maybe<AutoNoJSAPI>nojsapi;if(!aContentModal){nojsapi.emplace();}rv=pwwatch->OpenWindow2(AsOuter(),url.get(),name_ptr,options_ptr,/* aCalledFromScript = */false,aDialog,aNavigate,aExtraArgument,isPopupSpamWindow,forceNoOpener,aLoadInfo,getter_AddRefs(domReturn));}}NS_ENSURE_SUCCESS(rv,rv);// success!NS_ENSURE_TRUE(domReturn,NS_OK);nsCOMPtr<nsPIDOMWindowOuter>outerReturn=nsPIDOMWindowOuter::From(domReturn);outerReturn.swap(*aReturn);if(aDoJSFixups){nsCOMPtr<nsIDOMChromeWindow>chrome_win(do_QueryInterface(*aReturn));if(!chrome_win){// A new non-chrome window was created from a call to// window.open() from JavaScript, make sure there's a document in// the new window. We do this by simply asking the new window for// its document, this will synchronously create an empty document// if there is no document in the window.// XXXbz should this just use EnsureInnerWindow()?// Force document creation.nsCOMPtr<nsIDocument>doc=(*aReturn)->GetDoc();Unused<<doc;}}returnrv;}//*****************************************************************************// nsGlobalWindow: Timeout Functions//*****************************************************************************nsGlobalWindow*nsGlobalWindow::InnerForSetTimeoutOrInterval(ErrorResult&aError){nsGlobalWindow*currentInner;nsGlobalWindow*forwardTo;if(IsInnerWindow()){nsGlobalWindow*outer=GetOuterWindowInternal();currentInner=outer?outer->GetCurrentInnerWindowInternal():this;forwardTo=this;}else{currentInner=GetCurrentInnerWindowInternal();// This needs to forward to the inner window, but since the current// inner may not be the inner in the calling scope, we need to treat// this specially here as we don't want timeouts registered in a// dying inner window to get registered and run on the current inner// window. To get this right, we need to forward this call to the// inner window that's calling window.setTimeout().forwardTo=CallerInnerWindow();if(!forwardTo&&nsContentUtils::IsCallerChrome()){forwardTo=currentInner;}if(!forwardTo){aError.Throw(NS_ERROR_NOT_AVAILABLE);returnnullptr;}// If the caller and the callee share the same outer window, forward to the// caller inner. Else, we forward to the current inner (e.g. someone is// calling setTimeout() on a reference to some other window).if(forwardTo->GetOuterWindow()!=AsOuter()||!forwardTo->IsInnerWindow()){if(!currentInner){NS_WARNING("No inner window available!");aError.Throw(NS_ERROR_NOT_INITIALIZED);returnnullptr;}returncurrentInner;}}// If forwardTo is not the window with an active document then we want the// call to setTimeout/Interval to be a noop, so return null but don't set an// error.returnforwardTo->AsInner()->HasActiveDocument()?currentInner:nullptr;}int32_tnsGlobalWindow::SetTimeout(JSContext*aCx,Function&aFunction,int32_taTimeout,constSequence<JS::Value>&aArguments,ErrorResult&aError){returnSetTimeoutOrInterval(aCx,aFunction,aTimeout,aArguments,false,aError);}int32_tnsGlobalWindow::SetTimeout(JSContext*aCx,constnsAString&aHandler,int32_taTimeout,constSequence<JS::Value>&/* unused */,ErrorResult&aError){returnSetTimeoutOrInterval(aCx,aHandler,aTimeout,false,aError);}staticboolIsInterval(constOptional<int32_t>&aTimeout,int32_t&aResultTimeout){if(aTimeout.WasPassed()){aResultTimeout=aTimeout.Value();returntrue;}// If no interval was specified, treat this like a timeout, to avoid setting// an interval of 0 milliseconds.aResultTimeout=0;returnfalse;}int32_tnsGlobalWindow::SetInterval(JSContext*aCx,Function&aFunction,constOptional<int32_t>&aTimeout,constSequence<JS::Value>&aArguments,ErrorResult&aError){int32_ttimeout;boolisInterval=IsInterval(aTimeout,timeout);returnSetTimeoutOrInterval(aCx,aFunction,timeout,aArguments,isInterval,aError);}int32_tnsGlobalWindow::SetInterval(JSContext*aCx,constnsAString&aHandler,constOptional<int32_t>&aTimeout,constSequence<JS::Value>&/* unused */,ErrorResult&aError){int32_ttimeout;boolisInterval=IsInterval(aTimeout,timeout);returnSetTimeoutOrInterval(aCx,aHandler,timeout,isInterval,aError);}int32_tnsGlobalWindow::SetTimeoutOrInterval(JSContext*aCx,Function&aFunction,int32_taTimeout,constSequence<JS::Value>&aArguments,boolaIsInterval,ErrorResult&aError){nsGlobalWindow*inner=InnerForSetTimeoutOrInterval(aError);if(!inner){return-1;}if(inner!=this){returninner->SetTimeoutOrInterval(aCx,aFunction,aTimeout,aArguments,aIsInterval,aError);}nsCOMPtr<nsIScriptTimeoutHandler>handler=NS_CreateJSTimeoutHandler(aCx,this,aFunction,aArguments,aError);if(!handler){return0;}int32_tresult;aError=mTimeoutManager->SetTimeout(handler,aTimeout,aIsInterval,Timeout::Reason::eTimeoutOrInterval,&result);returnresult;}int32_tnsGlobalWindow::SetTimeoutOrInterval(JSContext*aCx,constnsAString&aHandler,int32_taTimeout,boolaIsInterval,ErrorResult&aError){nsGlobalWindow*inner=InnerForSetTimeoutOrInterval(aError);if(!inner){return-1;}if(inner!=this){returninner->SetTimeoutOrInterval(aCx,aHandler,aTimeout,aIsInterval,aError);}nsCOMPtr<nsIScriptTimeoutHandler>handler=NS_CreateJSTimeoutHandler(aCx,this,aHandler,aError);if(!handler){return0;}int32_tresult;aError=mTimeoutManager->SetTimeout(handler,aTimeout,aIsInterval,Timeout::Reason::eTimeoutOrInterval,&result);returnresult;}boolnsGlobalWindow::RunTimeoutHandler(Timeout*aTimeout,nsIScriptContext*aScx){MOZ_ASSERT(IsInnerWindow());// Hold on to the timeout in case mExpr or mFunObj releases its// doc.RefPtr<Timeout>timeout=aTimeout;Timeout*last_running_timeout=mTimeoutManager->BeginRunningTimeout(timeout);timeout->mRunning=true;// Push this timeout's popup control state, which should only be// eabled the first time a timeout fires that was created while// popups were enabled and with a delay less than// "dom.disable_open_click_delay".nsAutoPopupStatePusherpopupStatePusher(timeout->mPopupState);// Clear the timeout's popup state, if any, to prevent interval// timeouts from repeatedly opening poups.timeout->mPopupState=openAbused;booltrackNestingLevel=!timeout->mIsInterval;uint32_tnestingLevel;if(trackNestingLevel){nestingLevel=TimeoutManager::GetNestingLevel();TimeoutManager::SetNestingLevel(timeout->mNestingLevel);}constchar*reason;if(timeout->mIsInterval){reason="setInterval handler";}else{reason="setTimeout handler";}boolabortIntervalHandler=false;nsCOMPtr<nsIScriptTimeoutHandler>handler(do_QueryInterface(timeout->mScriptHandler));if(handler){RefPtr<Function>callback=handler->GetCallback();if(!callback){// Evaluate the timeout expression.constnsAString&script=handler->GetHandlerText();constchar*filename=nullptr;uint32_tlineNo=0,dummyColumn=0;handler->GetLocation(&filename,&lineNo,&dummyColumn);// New script entry point required, due to the "Create a script" sub-step of// http://www.whatwg.org/specs/web-apps/current-work/#timer-initialisation-stepsnsAutoMicroTaskmt;AutoEntryScriptaes(this,reason,true);JS::CompileOptionsoptions(aes.cx());options.setFileAndLine(filename,lineNo).setVersion(JSVERSION_DEFAULT);options.setNoScriptRval(true);JS::Rooted<JSObject*>global(aes.cx(),FastGetGlobalJSObject());nsresultrv=NS_OK;{nsJSUtils::ExecutionContextexec(aes.cx(),global);rv=exec.CompileAndExec(options,script);}if(rv==NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW_UNCATCHABLE){abortIntervalHandler=true;}}else{// Hold strong ref to ourselves while we call the callback.nsCOMPtr<nsISupports>me(static_cast<nsIDOMWindow*>(this));ErrorResultrv;JS::Rooted<JS::Value>ignoredVal(RootingCx());callback->Call(me,handler->GetArgs(),&ignoredVal,rv,reason);if(rv.IsUncatchableException()){abortIntervalHandler=true;}rv.SuppressException();}}else{nsCOMPtr<nsITimeoutHandler>basicHandler(timeout->mScriptHandler);nsCOMPtr<nsISupports>kungFuDeathGrip(static_cast<nsIDOMWindow*>(this));mozilla::Unused<<kungFuDeathGrip;basicHandler->Call();}// If we received an uncatchable exception, do not schedule the timeout again.// This allows the slow script dialog to break easy DoS attacks like// setInterval(function() { while(1); }, 100);if(abortIntervalHandler){// If it wasn't an interval timer to begin with, this does nothing. If it// was, we'll treat it as a timeout that we just ran and discard it when// we return.timeout->mIsInterval=false;}// We ignore any failures from calling EvaluateString() on the context or// Call() on a Function here since we're in a loop// where we're likely to be running timeouts whose OS timers// didn't fire in time and we don't want to not fire those timers// now just because execution of one timer failed. We can't// propagate the error to anyone who cares about it from this// point anyway, and the script context should have already reported// the script error in the usual way - so we just drop it.// Since we might be processing more timeouts, go ahead and flush the promise// queue now before we do that. We need to do that while we're still in our// "running JS is safe" state (e.g. mRunningTimeout is set, timeout->mRunning// is false).Promise::PerformMicroTaskCheckpoint();if(trackNestingLevel){TimeoutManager::SetNestingLevel(nestingLevel);}mTimeoutManager->EndRunningTimeout(last_running_timeout);timeout->mRunning=false;returntimeout->mCleared;}//*****************************************************************************// nsGlobalWindow: Helper Functions//*****************************************************************************already_AddRefed<nsIDocShellTreeOwner>nsGlobalWindow::GetTreeOwner(){FORWARD_TO_OUTER(GetTreeOwner,(),nullptr);// If there's no docShellAsItem, this window must have been closed,// in that case there is no tree owner.if(!mDocShell){returnnullptr;}nsCOMPtr<nsIDocShellTreeOwner>treeOwner;mDocShell->GetTreeOwner(getter_AddRefs(treeOwner));returntreeOwner.forget();}already_AddRefed<nsIBaseWindow>nsGlobalWindow::GetTreeOwnerWindow(){MOZ_ASSERT(IsOuterWindow());nsCOMPtr<nsIDocShellTreeOwner>treeOwner;// If there's no mDocShell, this window must have been closed,// in that case there is no tree owner.if(mDocShell){mDocShell->GetTreeOwner(getter_AddRefs(treeOwner));}nsCOMPtr<nsIBaseWindow>baseWindow=do_QueryInterface(treeOwner);returnbaseWindow.forget();}already_AddRefed<nsIWebBrowserChrome>nsGlobalWindow::GetWebBrowserChrome(){nsCOMPtr<nsIDocShellTreeOwner>treeOwner=GetTreeOwner();nsCOMPtr<nsIWebBrowserChrome>browserChrome=do_GetInterface(treeOwner);returnbrowserChrome.forget();}nsIScrollableFrame*nsGlobalWindow::GetScrollFrame(){FORWARD_TO_OUTER(GetScrollFrame,(),nullptr);if(!mDocShell){returnnullptr;}nsCOMPtr<nsIPresShell>presShell=mDocShell->GetPresShell();if(presShell){returnpresShell->GetRootScrollFrameAsScrollable();}returnnullptr;}nsresultnsGlobalWindow::SecurityCheckURL(constchar*aURL){nsCOMPtr<nsPIDOMWindowInner>sourceWindow=do_QueryInterface(GetEntryGlobal());if(!sourceWindow){sourceWindow=AsOuter()->GetCurrentInnerWindow();}AutoJSContextcx;nsGlobalWindow*sourceWin=nsGlobalWindow::Cast(sourceWindow);JSAutoCompartmentac(cx,sourceWin->GetGlobalJSObject());// Resolve the baseURI, which could be relative to the calling window.//// Note the algorithm to get the base URI should match the one// used to actually kick off the load in nsWindowWatcher.cpp.nsCOMPtr<nsIDocument>doc=sourceWindow->GetDoc();nsIURI*baseURI=nullptr;autoencoding=UTF_8_ENCODING;// default to utf-8if(doc){baseURI=doc->GetDocBaseURI();encoding=doc->GetDocumentCharacterSet();}nsCOMPtr<nsIURI>uri;nsresultrv=NS_NewURI(getter_AddRefs(uri),nsDependentCString(aURL),encoding,baseURI);if(NS_WARN_IF(NS_FAILED(rv))){returnrv;}if(NS_FAILED(nsContentUtils::GetSecurityManager()->CheckLoadURIFromScript(cx,uri))){returnNS_ERROR_FAILURE;}returnNS_OK;}boolnsGlobalWindow::IsPrivateBrowsing(){nsCOMPtr<nsILoadContext>loadContext=do_QueryInterface(GetDocShell());returnloadContext&&loadContext->UsePrivateBrowsing();}voidnsGlobalWindow::FlushPendingNotifications(FlushTypeaType){if(mDoc){mDoc->FlushPendingNotifications(aType);}}voidnsGlobalWindow::EnsureSizeAndPositionUpToDate(){MOZ_ASSERT(IsOuterWindow());// If we're a subframe, make sure our size is up to date. It's OK that this// crosses the content/chrome boundary, since chrome can have pending reflows// too.nsGlobalWindow*parent=nsGlobalWindow::Cast(GetPrivateParent());if(parent){parent->FlushPendingNotifications(FlushType::Layout);}}already_AddRefed<nsISupports>nsGlobalWindow::SaveWindowState(){NS_PRECONDITION(IsOuterWindow(),"Can't save the inner window's state");if(!mContext||!GetWrapperPreserveColor()){// The window may be getting torn down; don't bother saving state.returnnullptr;}nsGlobalWindow*inner=GetCurrentInnerWindowInternal();NS_ASSERTION(inner,"No inner window to save");// Don't do anything else to this inner window! After this point, all// calls to SetTimeoutOrInterval will create entries in the timeout// list that will only run after this window has come out of the bfcache.// Also, while we're frozen, we won't dispatch online/offline events// to the page.inner->Freeze();nsCOMPtr<nsISupports>state=newWindowStateHolder(inner);#ifdef DEBUG_PAGE_CACHEprintf("saving window state, state = %p\n",(void*)state);#endifreturnstate.forget();}nsresultnsGlobalWindow::RestoreWindowState(nsISupports*aState){NS_ASSERTION(IsOuterWindow(),"Cannot restore an inner window");if(!mContext||!GetWrapperPreserveColor()){// The window may be getting torn down; don't bother restoring state.returnNS_OK;}nsCOMPtr<WindowStateHolder>holder=do_QueryInterface(aState);NS_ENSURE_TRUE(holder,NS_ERROR_FAILURE);#ifdef DEBUG_PAGE_CACHEprintf("restoring window state, state = %p\n",(void*)holder);#endif// And we're ready to go!nsGlobalWindow*inner=GetCurrentInnerWindowInternal();// if a link is focused, refocus with the FLAG_SHOWRING flag set. This makes// it easy to tell which link was last clicked when going back a page.nsIContent*focusedNode=inner->GetFocusedNode();if(IsLink(focusedNode)){nsIFocusManager*fm=nsFocusManager::GetFocusManager();if(fm){nsCOMPtr<nsIDOMElement>focusedElement(do_QueryInterface(focusedNode));fm->SetFocus(focusedElement,nsIFocusManager::FLAG_NOSCROLL|nsIFocusManager::FLAG_SHOWRING);}}inner->Thaw();holder->DidRestoreWindow();returnNS_OK;}voidnsGlobalWindow::EnableDeviceSensor(uint32_taType){MOZ_ASSERT(IsInnerWindow());boolalreadyEnabled=false;for(uint32_ti=0;i<mEnabledSensors.Length();i++){if(mEnabledSensors[i]==aType){alreadyEnabled=true;break;}}mEnabledSensors.AppendElement(aType);if(alreadyEnabled){return;}nsCOMPtr<nsIDeviceSensors>ac=do_GetService(NS_DEVICE_SENSORS_CONTRACTID);if(ac){ac->AddWindowListener(aType,this);}}voidnsGlobalWindow::DisableDeviceSensor(uint32_taType){MOZ_ASSERT(IsInnerWindow());int32_tdoomedElement=-1;int32_tlistenerCount=0;for(uint32_ti=0;i<mEnabledSensors.Length();i++){if(mEnabledSensors[i]==aType){doomedElement=i;listenerCount++;}}if(doomedElement==-1){return;}mEnabledSensors.RemoveElementAt(doomedElement);if(listenerCount>1){return;}nsCOMPtr<nsIDeviceSensors>ac=do_GetService(NS_DEVICE_SENSORS_CONTRACTID);if(ac){ac->RemoveWindowListener(aType,this);}}#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)voidnsGlobalWindow::EnableOrientationChangeListener(){MOZ_ASSERT(IsInnerWindow());if(!nsContentUtils::ShouldResistFingerprinting(mDocShell)&&!mOrientationChangeObserver){mOrientationChangeObserver=newWindowOrientationObserver(this);}}voidnsGlobalWindow::DisableOrientationChangeListener(){MOZ_ASSERT(IsInnerWindow());mOrientationChangeObserver=nullptr;}#endifvoidnsGlobalWindow::SetHasGamepadEventListener(boolaHasGamepad/* = true*/){MOZ_ASSERT(IsInnerWindow());mHasGamepad=aHasGamepad;if(aHasGamepad){EnableGamepadUpdates();}}voidnsGlobalWindow::EventListenerAdded(nsIAtom*aType){if(aType==nsGkAtoms::onvrdisplayactivate||aType==nsGkAtoms::onvrdisplayconnect||aType==nsGkAtoms::onvrdisplaydeactivate||aType==nsGkAtoms::onvrdisplaydisconnect||aType==nsGkAtoms::onvrdisplaypresentchange){NotifyVREventListenerAdded();}if(aType==nsGkAtoms::onvrdisplayactivate){mHasVRDisplayActivateEvents=true;}if(aType==nsGkAtoms::onbeforeunload&&mTabChild&&(!mDoc||!(mDoc->GetSandboxFlags()&SANDBOXED_MODALS))){MOZ_ASSERT(IsInnerWindow());mBeforeUnloadListenerCount++;MOZ_ASSERT(mBeforeUnloadListenerCount>0);mTabChild->BeforeUnloadAdded();}// We need to initialize localStorage in order to receive notifications.if(aType==nsGkAtoms::onstorage){ErrorResultrv;GetLocalStorage(rv);rv.SuppressException();}}voidnsGlobalWindow::EventListenerRemoved(nsIAtom*aType){if(aType==nsGkAtoms::onbeforeunload&&mTabChild&&(!mDoc||!(mDoc->GetSandboxFlags()&SANDBOXED_MODALS))){MOZ_ASSERT(IsInnerWindow());mBeforeUnloadListenerCount--;MOZ_ASSERT(mBeforeUnloadListenerCount>=0);mTabChild->BeforeUnloadRemoved();}}voidnsGlobalWindow::NotifyVREventListenerAdded(){MOZ_ASSERT(IsInnerWindow());mHasVREvents=true;EnableVRUpdates();}boolnsGlobalWindow::HasUsedVR()const{MOZ_ASSERT(IsInnerWindow());// Returns true only if any WebVR API call or related event// has been usedreturnmHasVREvents;}boolnsGlobalWindow::IsVRContentDetected()const{MOZ_ASSERT(IsInnerWindow());// Returns true only if the content will respond to// the VRDisplayActivate event.returnmHasVRDisplayActivateEvents;}boolnsGlobalWindow::IsVRContentPresenting()const{for(constauto&display:mVRDisplays){if(display->IsAnyPresenting(gfx::kVRGroupAll)){returntrue;}}returnfalse;}voidnsGlobalWindow::EnableTimeChangeNotifications(){mozilla::time::AddWindowListener(AsInner());}voidnsGlobalWindow::DisableTimeChangeNotifications(){mozilla::time::RemoveWindowListener(AsInner());}voidnsGlobalWindow::AddSizeOfIncludingThis(nsWindowSizes*aWindowSizes)const{aWindowSizes->mDOMOtherSize+=aWindowSizes->mMallocSizeOf(this);if(IsInnerWindow()){EventListenerManager*elm=GetExistingListenerManager();if(elm){aWindowSizes->mDOMOtherSize+=elm->SizeOfIncludingThis(aWindowSizes->mMallocSizeOf);aWindowSizes->mDOMEventListenersCount+=elm->ListenerCount();}if(mDoc){// Multiple global windows can share a document. So only measure the// document if it (a) doesn't have a global window, or (b) it's the// primary document for the window.if(!mDoc->GetInnerWindow()||mDoc->GetInnerWindow()==AsInner()){mDoc->DocAddSizeOfIncludingThis(aWindowSizes);}}}if(mNavigator){aWindowSizes->mDOMOtherSize+=mNavigator->SizeOfIncludingThis(aWindowSizes->mMallocSizeOf);}aWindowSizes->mDOMEventTargetsSize+=mEventTargetObjects.ShallowSizeOfExcludingThis(aWindowSizes->mMallocSizeOf);for(autoiter=mEventTargetObjects.ConstIter();!iter.Done();iter.Next()){DOMEventTargetHelper*et=iter.Get()->GetKey();if(nsCOMPtr<nsISizeOfEventTarget>iSizeOf=do_QueryObject(et)){aWindowSizes->mDOMEventTargetsSize+=iSizeOf->SizeOfEventTargetIncludingThis(aWindowSizes->mMallocSizeOf);}if(EventListenerManager*elm=et->GetExistingListenerManager()){aWindowSizes->mDOMEventListenersCount+=elm->ListenerCount();}++aWindowSizes->mDOMEventTargetsCount;}}voidnsGlobalWindow::AddGamepad(uint32_taIndex,Gamepad*aGamepad){MOZ_ASSERT(IsInnerWindow());// Create the index we will present to content based on which indices are// already taken, as required by the spec.// https://w3c.github.io/gamepad/gamepad.html#widl-Gamepad-indexintindex=0;while(mGamepadIndexSet.Contains(index)){++index;}mGamepadIndexSet.Put(index);aGamepad->SetIndex(index);mGamepads.Put(aIndex,aGamepad);}voidnsGlobalWindow::RemoveGamepad(uint32_taIndex){MOZ_ASSERT(IsInnerWindow());RefPtr<Gamepad>gamepad;if(!mGamepads.Get(aIndex,getter_AddRefs(gamepad))){return;}// Free up the index we were using so it can be reusedmGamepadIndexSet.Remove(gamepad->Index());mGamepads.Remove(aIndex);}voidnsGlobalWindow::GetGamepads(nsTArray<RefPtr<Gamepad>>&aGamepads){MOZ_ASSERT(IsInnerWindow());aGamepads.Clear();// navigator.getGamepads() always returns an empty array when// privacy.resistFingerprinting is true.if(nsContentUtils::ShouldResistFingerprinting()){return;}// mGamepads.Count() may not be sufficient, but it's not harmful.aGamepads.SetCapacity(mGamepads.Count());for(autoiter=mGamepads.Iter();!iter.Done();iter.Next()){Gamepad*gamepad=iter.UserData();aGamepads.EnsureLengthAtLeast(gamepad->Index()+1);aGamepads[gamepad->Index()]=gamepad;}}already_AddRefed<Gamepad>nsGlobalWindow::GetGamepad(uint32_taIndex){MOZ_ASSERT(IsInnerWindow());RefPtr<Gamepad>gamepad;if(mGamepads.Get(aIndex,getter_AddRefs(gamepad))){returngamepad.forget();}returnnullptr;}voidnsGlobalWindow::SetHasSeenGamepadInput(boolaHasSeen){MOZ_ASSERT(IsInnerWindow());mHasSeenGamepadInput=aHasSeen;}boolnsGlobalWindow::HasSeenGamepadInput(){MOZ_ASSERT(IsInnerWindow());returnmHasSeenGamepadInput;}voidnsGlobalWindow::SyncGamepadState(){MOZ_ASSERT(IsInnerWindow());if(mHasSeenGamepadInput){RefPtr<GamepadManager>gamepadManager(GamepadManager::GetService());for(autoiter=mGamepads.Iter();!iter.Done();iter.Next()){gamepadManager->SyncGamepadState(iter.Key(),iter.UserData());}}}voidnsGlobalWindow::StopGamepadHaptics(){MOZ_ASSERT(IsInnerWindow());if(mHasSeenGamepadInput){RefPtr<GamepadManager>gamepadManager(GamepadManager::GetService());gamepadManager->StopHaptics();}}boolnsGlobalWindow::UpdateVRDisplays(nsTArray<RefPtr<mozilla::dom::VRDisplay>>&aDevices){FORWARD_TO_INNER(UpdateVRDisplays,(aDevices),false);VRDisplay::UpdateVRDisplays(mVRDisplays,AsInner());aDevices=mVRDisplays;returntrue;}voidnsGlobalWindow::NotifyActiveVRDisplaysChanged(){MOZ_ASSERT(IsInnerWindow());if(mNavigator){mNavigator->NotifyActiveVRDisplaysChanged();}}uint32_tnsGlobalWindow::GetAutoActivateVRDisplayID(){MOZ_ASSERT(IsOuterWindow());uint32_tretVal=mAutoActivateVRDisplayID;mAutoActivateVRDisplayID=0;returnretVal;}voidnsGlobalWindow::SetAutoActivateVRDisplayID(uint32_taAutoActivateVRDisplayID){MOZ_ASSERT(IsOuterWindow());mAutoActivateVRDisplayID=aAutoActivateVRDisplayID;}voidnsGlobalWindow::DispatchVRDisplayActivate(uint32_taDisplayID,mozilla::dom::VRDisplayEventReasonaReason){// Search for the display identified with aDisplayID and fire the// event if found.for(constauto&display:mVRDisplays){if(display->DisplayId()==aDisplayID){if(aReason!=VRDisplayEventReason::Navigation&&display->IsAnyPresenting(gfx::kVRGroupContent)){// We only want to trigger this event if nobody is presenting to the// display already or when a page is loaded by navigating away// from a page with an active VR Presentation.continue;}VRDisplayEventInitinit;init.mBubbles=false;init.mCancelable=false;init.mDisplay=display;init.mReason.Construct(aReason);RefPtr<VRDisplayEvent>event=VRDisplayEvent::Constructor(this,NS_LITERAL_STRING("vrdisplayactivate"),init);// vrdisplayactivate is a trusted event, allowing VRDisplay.requestPresent// to be used in response to link traversal, user request (chrome UX), and// HMD mounting detection sensors.event->SetTrusted(true);booldefaultActionEnabled;// VRDisplay.requestPresent normally requires a user gesture; however, an// exception is made to allow it to be called in response to vrdisplayactivate// during VR link traversal.display->StartHandlingVRNavigationEvent();Unused<<DispatchEvent(event,&defaultActionEnabled);display->StopHandlingVRNavigationEvent();// Once we dispatch the event, we must not access any members as an event// listener can do anything, including closing windows.return;}}}voidnsGlobalWindow::DispatchVRDisplayDeactivate(uint32_taDisplayID,mozilla::dom::VRDisplayEventReasonaReason){// Search for the display identified with aDisplayID and fire the// event if found.for(constauto&display:mVRDisplays){if(display->DisplayId()==aDisplayID&&display->IsPresenting()){// We only want to trigger this event to content that is presenting to// the display already.VRDisplayEventInitinit;init.mBubbles=false;init.mCancelable=false;init.mDisplay=display;init.mReason.Construct(aReason);RefPtr<VRDisplayEvent>event=VRDisplayEvent::Constructor(this,NS_LITERAL_STRING("vrdisplaydeactivate"),init);event->SetTrusted(true);booldefaultActionEnabled;Unused<<DispatchEvent(event,&defaultActionEnabled);// Once we dispatch the event, we must not access any members as an event// listener can do anything, including closing windows.return;}}}voidnsGlobalWindow::DispatchVRDisplayConnect(uint32_taDisplayID){// Search for the display identified with aDisplayID and fire the// event if found.for(constauto&display:mVRDisplays){if(display->DisplayId()==aDisplayID){// Fire event even if not presenting to the display.VRDisplayEventInitinit;init.mBubbles=false;init.mCancelable=false;init.mDisplay=display;// VRDisplayEvent.reason is not set for vrdisplayconnectRefPtr<VRDisplayEvent>event=VRDisplayEvent::Constructor(this,NS_LITERAL_STRING("vrdisplayconnect"),init);event->SetTrusted(true);booldefaultActionEnabled;Unused<<DispatchEvent(event,&defaultActionEnabled);// Once we dispatch the event, we must not access any members as an event// listener can do anything, including closing windows.return;}}}voidnsGlobalWindow::DispatchVRDisplayDisconnect(uint32_taDisplayID){// Search for the display identified with aDisplayID and fire the// event if found.for(constauto&display:mVRDisplays){if(display->DisplayId()==aDisplayID){// Fire event even if not presenting to the display.VRDisplayEventInitinit;init.mBubbles=false;init.mCancelable=false;init.mDisplay=display;// VRDisplayEvent.reason is not set for vrdisplaydisconnectRefPtr<VRDisplayEvent>event=VRDisplayEvent::Constructor(this,NS_LITERAL_STRING("vrdisplaydisconnect"),init);event->SetTrusted(true);booldefaultActionEnabled;Unused<<DispatchEvent(event,&defaultActionEnabled);// Once we dispatch the event, we must not access any members as an event// listener can do anything, including closing windows.return;}}}voidnsGlobalWindow::DispatchVRDisplayPresentChange(uint32_taDisplayID){// Search for the display identified with aDisplayID and fire the// event if found.for(constauto&display:mVRDisplays){if(display->DisplayId()==aDisplayID){// Fire event even if not presenting to the display.VRDisplayEventInitinit;init.mBubbles=false;init.mCancelable=false;init.mDisplay=display;// VRDisplayEvent.reason is not set for vrdisplaypresentchangeRefPtr<VRDisplayEvent>event=VRDisplayEvent::Constructor(this,NS_LITERAL_STRING("vrdisplaypresentchange"),init);event->SetTrusted(true);booldefaultActionEnabled;Unused<<DispatchEvent(event,&defaultActionEnabled);// Once we dispatch the event, we must not access any members as an event// listener can do anything, including closing windows.return;}}}// nsGlobalChromeWindow implementationNS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalChromeWindow)NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsGlobalChromeWindow,nsGlobalWindow)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowserDOMWindow)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessageManager)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGroupMessageManagers)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOpenerForInitialContentBrowser)NS_IMPL_CYCLE_COLLECTION_TRAVERSE_ENDNS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsGlobalChromeWindow,nsGlobalWindow)NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowserDOMWindow)if(tmp->mMessageManager){static_cast<nsFrameMessageManager*>(tmp->mMessageManager.get())->Disconnect();NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessageManager)}tmp->DisconnectAndClearGroupMessageManagers();NS_IMPL_CYCLE_COLLECTION_UNLINK(mGroupMessageManagers)NS_IMPL_CYCLE_COLLECTION_UNLINK(mOpenerForInitialContentBrowser)NS_IMPL_CYCLE_COLLECTION_UNLINK_END// QueryInterface implementation for nsGlobalChromeWindowNS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsGlobalChromeWindow)NS_INTERFACE_MAP_ENTRY(nsIDOMChromeWindow)NS_INTERFACE_MAP_END_INHERITING(nsGlobalWindow)NS_IMPL_ADDREF_INHERITED(nsGlobalChromeWindow,nsGlobalWindow)NS_IMPL_RELEASE_INHERITED(nsGlobalChromeWindow,nsGlobalWindow)/* static */already_AddRefed<nsGlobalChromeWindow>nsGlobalChromeWindow::Create(nsGlobalWindow*aOuterWindow){RefPtr<nsGlobalChromeWindow>window=newnsGlobalChromeWindow(aOuterWindow);window->InitWasOffline();returnwindow.forget();}NS_IMETHODIMPnsGlobalChromeWindow::GetWindowState(uint16_t*aWindowState){FORWARD_TO_INNER_CHROME(GetWindowState,(aWindowState),NS_ERROR_UNEXPECTED);*aWindowState=WindowState();returnNS_OK;}uint16_tnsGlobalWindow::WindowState(){MOZ_ASSERT(IsInnerWindow());nsCOMPtr<nsIWidget>widget=GetMainWidget();int32_tmode=widget?widget->SizeMode():0;switch(mode){casensSizeMode_Minimized:returnnsIDOMChromeWindow::STATE_MINIMIZED;casensSizeMode_Maximized:returnnsIDOMChromeWindow::STATE_MAXIMIZED;casensSizeMode_Fullscreen:returnnsIDOMChromeWindow::STATE_FULLSCREEN;casensSizeMode_Normal:returnnsIDOMChromeWindow::STATE_NORMAL;default:NS_WARNING("Illegal window state for this chrome window");break;}returnnsIDOMChromeWindow::STATE_NORMAL;}boolnsGlobalWindow::IsFullyOccluded(){MOZ_ASSERT(IsInnerWindow());nsCOMPtr<nsIWidget>widget=GetMainWidget();returnwidget&&widget->IsFullyOccluded();}NS_IMETHODIMPnsGlobalChromeWindow::Maximize(){FORWARD_TO_INNER_CHROME(Maximize,(),NS_ERROR_UNEXPECTED);nsGlobalWindow::Maximize();returnNS_OK;}voidnsGlobalWindow::Maximize(){MOZ_ASSERT(IsInnerWindow());nsCOMPtr<nsIWidget>widget=GetMainWidget();if(widget){widget->SetSizeMode(nsSizeMode_Maximized);}}NS_IMETHODIMPnsGlobalChromeWindow::Minimize(){FORWARD_TO_INNER_CHROME(Minimize,(),NS_ERROR_UNEXPECTED);nsGlobalWindow::Minimize();returnNS_OK;}voidnsGlobalWindow::Minimize(){MOZ_ASSERT(IsInnerWindow());nsCOMPtr<nsIWidget>widget=GetMainWidget();if(widget){widget->SetSizeMode(nsSizeMode_Minimized);}}NS_IMETHODIMPnsGlobalChromeWindow::Restore(){FORWARD_TO_INNER_CHROME(Restore,(),NS_ERROR_UNEXPECTED);nsGlobalWindow::Restore();returnNS_OK;}voidnsGlobalWindow::Restore(){MOZ_ASSERT(IsInnerWindow());nsCOMPtr<nsIWidget>widget=GetMainWidget();if(widget){widget->SetSizeMode(nsSizeMode_Normal);}}NS_IMETHODIMPnsGlobalChromeWindow::GetAttention(){FORWARD_TO_INNER_CHROME(GetAttention,(),NS_ERROR_UNEXPECTED);ErrorResultrv;GetAttention(rv);returnrv.StealNSResult();}voidnsGlobalWindow::GetAttention(ErrorResult&aResult){MOZ_ASSERT(IsInnerWindow());returnGetAttentionWithCycleCount(-1,aResult);}NS_IMETHODIMPnsGlobalChromeWindow::GetAttentionWithCycleCount(int32_taCycleCount){FORWARD_TO_INNER_CHROME(GetAttentionWithCycleCount,(aCycleCount),NS_ERROR_UNEXPECTED);ErrorResultrv;GetAttentionWithCycleCount(aCycleCount,rv);returnrv.StealNSResult();}voidnsGlobalWindow::GetAttentionWithCycleCount(int32_taCycleCount,ErrorResult&aError){MOZ_ASSERT(IsInnerWindow());nsCOMPtr<nsIWidget>widget=GetMainWidget();if(widget){aError=widget->GetAttention(aCycleCount);}}NS_IMETHODIMPnsGlobalChromeWindow::BeginWindowMove(nsIDOMEvent*aMouseDownEvent,nsIDOMElement*aPanel){FORWARD_TO_INNER_CHROME(BeginWindowMove,(aMouseDownEvent,aPanel),NS_ERROR_UNEXPECTED);NS_ENSURE_TRUE(aMouseDownEvent,NS_ERROR_FAILURE);Event*mouseDownEvent=aMouseDownEvent->InternalDOMEvent();NS_ENSURE_TRUE(mouseDownEvent,NS_ERROR_FAILURE);nsCOMPtr<Element>panel=do_QueryInterface(aPanel);NS_ENSURE_TRUE(panel||!aPanel,NS_ERROR_FAILURE);ErrorResultrv;BeginWindowMove(*mouseDownEvent,panel,rv);returnrv.StealNSResult();}voidnsGlobalWindow::BeginWindowMove(Event&aMouseDownEvent,Element*aPanel,ErrorResult&aError){MOZ_ASSERT(IsInnerWindow());nsCOMPtr<nsIWidget>widget;// if a panel was supplied, use its widget instead.#ifdef MOZ_XULif(aPanel){nsIFrame*frame=aPanel->GetPrimaryFrame();if(!frame||!frame->IsMenuPopupFrame()){return;}widget=(static_cast<nsMenuPopupFrame*>(frame))->GetWidget();}else{#endifwidget=GetMainWidget();#ifdef MOZ_XUL}#endifif(!widget){return;}WidgetMouseEvent*mouseEvent=aMouseDownEvent.WidgetEventPtr()->AsMouseEvent();if(!mouseEvent||mouseEvent->mClass!=eMouseEventClass){aError.Throw(NS_ERROR_FAILURE);return;}aError=widget->BeginMoveDrag(mouseEvent);}already_AddRefed<nsWindowRoot>nsGlobalWindow::GetWindowRootOuter(){MOZ_RELEASE_ASSERT(IsOuterWindow());nsCOMPtr<nsPIWindowRoot>root=GetTopWindowRoot();returnroot.forget().downcast<nsWindowRoot>();}already_AddRefed<nsWindowRoot>nsGlobalWindow::GetWindowRoot(mozilla::ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(GetWindowRootOuter,(),aError,nullptr);}//Note: This call will lock the cursor, it will not change as it moves.//To unlock, the cursor must be set back to CURSOR_AUTO.NS_IMETHODIMPnsGlobalChromeWindow::SetCursor(constnsAString&aCursor){FORWARD_TO_INNER_CHROME(SetCursor,(aCursor),NS_ERROR_UNEXPECTED);ErrorResultrv;SetCursor(aCursor,rv);returnrv.StealNSResult();}voidnsGlobalWindow::SetCursorOuter(constnsAString&aCursor,ErrorResult&aError){MOZ_RELEASE_ASSERT(IsOuterWindow());int32_tcursor;if(aCursor.EqualsLiteral("auto"))cursor=NS_STYLE_CURSOR_AUTO;else{nsCSSKeywordkeyword=nsCSSKeywords::LookupKeyword(aCursor);if(!nsCSSProps::FindKeyword(keyword,nsCSSProps::kCursorKTable,cursor)){return;}}RefPtr<nsPresContext>presContext;if(mDocShell){mDocShell->GetPresContext(getter_AddRefs(presContext));}if(presContext){// Need root widget.nsCOMPtr<nsIPresShell>presShell=mDocShell->GetPresShell();if(!presShell){aError.Throw(NS_ERROR_FAILURE);return;}nsViewManager*vm=presShell->GetViewManager();if(!vm){aError.Throw(NS_ERROR_FAILURE);return;}nsView*rootView=vm->GetRootView();if(!rootView){aError.Throw(NS_ERROR_FAILURE);return;}nsIWidget*widget=rootView->GetNearestWidget(nullptr);if(!widget){aError.Throw(NS_ERROR_FAILURE);return;}// Call esm and set cursor.aError=presContext->EventStateManager()->SetCursor(cursor,nullptr,false,0.0f,0.0f,widget,true);}}voidnsGlobalWindow::SetCursor(constnsAString&aCursor,ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(SetCursorOuter,(aCursor,aError),aError,);}NS_IMETHODIMPnsGlobalChromeWindow::GetBrowserDOMWindow(nsIBrowserDOMWindow**aBrowserWindow){FORWARD_TO_INNER_CHROME(GetBrowserDOMWindow,(aBrowserWindow),NS_ERROR_UNEXPECTED);ErrorResultrv;NS_IF_ADDREF(*aBrowserWindow=GetBrowserDOMWindow(rv));returnrv.StealNSResult();}nsIBrowserDOMWindow*nsGlobalWindow::GetBrowserDOMWindowOuter(){MOZ_RELEASE_ASSERT(IsOuterWindow());MOZ_ASSERT(IsChromeWindow());returnstatic_cast<nsGlobalChromeWindow*>(this)->mBrowserDOMWindow;}nsIBrowserDOMWindow*nsGlobalWindow::GetBrowserDOMWindow(ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(GetBrowserDOMWindowOuter,(),aError,nullptr);}NS_IMETHODIMPnsGlobalChromeWindow::SetBrowserDOMWindow(nsIBrowserDOMWindow*aBrowserWindow){FORWARD_TO_INNER_CHROME(SetBrowserDOMWindow,(aBrowserWindow),NS_ERROR_UNEXPECTED);ErrorResultrv;SetBrowserDOMWindow(aBrowserWindow,rv);returnrv.StealNSResult();}voidnsGlobalWindow::SetBrowserDOMWindowOuter(nsIBrowserDOMWindow*aBrowserWindow){MOZ_RELEASE_ASSERT(IsOuterWindow());MOZ_ASSERT(IsChromeWindow());static_cast<nsGlobalChromeWindow*>(this)->mBrowserDOMWindow=aBrowserWindow;}voidnsGlobalWindow::SetBrowserDOMWindow(nsIBrowserDOMWindow*aBrowserWindow,ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(SetBrowserDOMWindowOuter,(aBrowserWindow),aError,);}NS_IMETHODIMPnsGlobalChromeWindow::NotifyDefaultButtonLoaded(nsIDOMElement*aDefaultButton){FORWARD_TO_INNER_CHROME(NotifyDefaultButtonLoaded,(aDefaultButton),NS_ERROR_UNEXPECTED);nsCOMPtr<Element>defaultButton=do_QueryInterface(aDefaultButton);NS_ENSURE_ARG(defaultButton);ErrorResultrv;NotifyDefaultButtonLoaded(*defaultButton,rv);returnrv.StealNSResult();}voidnsGlobalWindow::NotifyDefaultButtonLoaded(Element&aDefaultButton,ErrorResult&aError){MOZ_ASSERT(IsInnerWindow());#ifdef MOZ_XUL// Don't snap to a disabled button.nsCOMPtr<nsIDOMXULControlElement>xulControl=do_QueryInterface(&aDefaultButton);if(!xulControl){aError.Throw(NS_ERROR_FAILURE);return;}booldisabled;aError=xulControl->GetDisabled(&disabled);if(aError.Failed()||disabled){return;}// Get the button rect in screen coordinates.nsIFrame*frame=aDefaultButton.GetPrimaryFrame();if(!frame){aError.Throw(NS_ERROR_FAILURE);return;}LayoutDeviceIntRectbuttonRect=LayoutDeviceIntRect::FromAppUnitsToNearest(frame->GetScreenRectInAppUnits(),frame->PresContext()->AppUnitsPerDevPixel());// Get the widget rect in screen coordinates.nsIWidget*widget=GetNearestWidget();if(!widget){aError.Throw(NS_ERROR_FAILURE);return;}LayoutDeviceIntRectwidgetRect=widget->GetScreenBounds();// Convert the buttonRect coordinates from screen to the widget.buttonRect-=widgetRect.TopLeft();nsresultrv=widget->OnDefaultButtonLoaded(buttonRect);if(NS_FAILED(rv)&&rv!=NS_ERROR_NOT_IMPLEMENTED){aError.Throw(rv);}#elseaError.Throw(NS_ERROR_NOT_IMPLEMENTED);#endif}NS_IMETHODIMPnsGlobalChromeWindow::GetMessageManager(nsIMessageBroadcaster**aManager){FORWARD_TO_INNER_CHROME(GetMessageManager,(aManager),NS_ERROR_UNEXPECTED);ErrorResultrv;NS_IF_ADDREF(*aManager=GetMessageManager(rv));returnrv.StealNSResult();}nsIMessageBroadcaster*nsGlobalWindow::GetMessageManager(ErrorResult&aError){MOZ_ASSERT(IsChromeWindow());MOZ_RELEASE_ASSERT(IsInnerWindow());nsGlobalChromeWindow*myself=static_cast<nsGlobalChromeWindow*>(this);if(!myself->mMessageManager){nsCOMPtr<nsIMessageBroadcaster>globalMM=do_GetService("@mozilla.org/globalmessagemanager;1");myself->mMessageManager=newnsFrameMessageManager(nullptr,static_cast<nsFrameMessageManager*>(globalMM.get()),MM_CHROME|MM_BROADCASTER);}returnmyself->mMessageManager;}NS_IMETHODIMPnsGlobalChromeWindow::GetGroupMessageManager(constnsAString&aGroup,nsIMessageBroadcaster**aManager){FORWARD_TO_INNER_CHROME(GetGroupMessageManager,(aGroup,aManager),NS_ERROR_UNEXPECTED);ErrorResultrv;NS_IF_ADDREF(*aManager=GetGroupMessageManager(aGroup,rv));returnrv.StealNSResult();}nsIMessageBroadcaster*nsGlobalWindow::GetGroupMessageManager(constnsAString&aGroup,ErrorResult&aError){MOZ_ASSERT(IsChromeWindow());MOZ_RELEASE_ASSERT(IsInnerWindow());nsGlobalChromeWindow*myself=static_cast<nsGlobalChromeWindow*>(this);nsCOMPtr<nsIMessageBroadcaster>messageManager=myself->mGroupMessageManagers.LookupForAdd(aGroup).OrInsert([this,&aError](){nsFrameMessageManager*parent=static_cast<nsFrameMessageManager*>(GetMessageManager(aError));returnnewnsFrameMessageManager(nullptr,parent,MM_CHROME|MM_BROADCASTER);});returnmessageManager;}nsresultnsGlobalChromeWindow::SetOpenerForInitialContentBrowser(mozIDOMWindowProxy*aOpenerWindow){MOZ_RELEASE_ASSERT(IsOuterWindow());MOZ_ASSERT(!mOpenerForInitialContentBrowser);mOpenerForInitialContentBrowser=aOpenerWindow;returnNS_OK;}nsresultnsGlobalChromeWindow::TakeOpenerForInitialContentBrowser(mozIDOMWindowProxy**aOpenerWindow){MOZ_RELEASE_ASSERT(IsOuterWindow());// Intentionally forget our own membermOpenerForInitialContentBrowser.forget(aOpenerWindow);returnNS_OK;}// nsGlobalModalWindow implementation// QueryInterface implementation for nsGlobalModalWindowNS_INTERFACE_MAP_BEGIN(nsGlobalModalWindow)NS_INTERFACE_MAP_ENTRY(nsIDOMModalContentWindow)NS_INTERFACE_MAP_END_INHERITING(nsGlobalWindow)NS_IMPL_ADDREF_INHERITED(nsGlobalModalWindow,nsGlobalWindow)NS_IMPL_RELEASE_INHERITED(nsGlobalModalWindow,nsGlobalWindow)voidnsGlobalWindow::GetDialogArgumentsOuter(JSContext*aCx,JS::MutableHandle<JS::Value>aRetval,nsIPrincipal&aSubjectPrincipal,ErrorResult&aError){MOZ_RELEASE_ASSERT(IsOuterWindow());MOZ_ASSERT(IsModalContentWindow(),"This should only be called on modal windows!");if(!mDialogArguments){MOZ_ASSERT(mIsClosed,"This window should be closed!");aRetval.setUndefined();return;}// This does an internal origin check, and returns undefined if the subject// does not subsumes the origin of the arguments.JS::Rooted<JSObject*>wrapper(aCx,GetWrapper());JSAutoCompartmentac(aCx,wrapper);mDialogArguments->Get(aCx,wrapper,&aSubjectPrincipal,aRetval,aError);}voidnsGlobalWindow::GetDialogArguments(JSContext*aCx,JS::MutableHandle<JS::Value>aRetval,nsIPrincipal&aSubjectPrincipal,ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(GetDialogArgumentsOuter,(aCx,aRetval,aSubjectPrincipal,aError),aError,);}/* static */already_AddRefed<nsGlobalModalWindow>nsGlobalModalWindow::Create(nsGlobalWindow*aOuterWindow){RefPtr<nsGlobalModalWindow>window=newnsGlobalModalWindow(aOuterWindow);window->InitWasOffline();returnwindow.forget();}NS_IMETHODIMPnsGlobalModalWindow::GetDialogArguments(nsIVariant**aArguments){FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(GetDialogArguments,(aArguments),NS_ERROR_NOT_INITIALIZED);// This does an internal origin check, and returns undefined if the subject// does not subsumes the origin of the arguments.returnmDialogArguments->Get(nsContentUtils::SubjectPrincipal(),aArguments);}/* static */already_AddRefed<nsGlobalWindow>nsGlobalWindow::Create(nsGlobalWindow*aOuterWindow){RefPtr<nsGlobalWindow>window=newnsGlobalWindow(aOuterWindow);window->InitWasOffline();returnwindow.forget();}voidnsGlobalWindow::InitWasOffline(){mWasOffline=NS_IsOffline();}voidnsGlobalWindow::GetReturnValueOuter(JSContext*aCx,JS::MutableHandle<JS::Value>aReturnValue,nsIPrincipal&aSubjectPrincipal,ErrorResult&aError){MOZ_RELEASE_ASSERT(IsOuterWindow());MOZ_ASSERT(IsModalContentWindow(),"This should only be called on modal windows!");if(mReturnValue){JS::Rooted<JSObject*>wrapper(aCx,GetWrapper());JSAutoCompartmentac(aCx,wrapper);mReturnValue->Get(aCx,wrapper,&aSubjectPrincipal,aReturnValue,aError);}else{aReturnValue.setUndefined();}}voidnsGlobalWindow::GetReturnValue(JSContext*aCx,JS::MutableHandle<JS::Value>aReturnValue,nsIPrincipal&aSubjectPrincipal,ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(GetReturnValueOuter,(aCx,aReturnValue,aSubjectPrincipal,aError),aError,);}NS_IMETHODIMPnsGlobalModalWindow::GetReturnValue(nsIVariant**aRetVal){FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(GetReturnValue,(aRetVal),NS_OK);if(!mReturnValue){nsCOMPtr<nsIVariant>variant=CreateVoidVariant();variant.forget(aRetVal);returnNS_OK;}returnmReturnValue->Get(nsContentUtils::SubjectPrincipal(),aRetVal);}voidnsGlobalWindow::SetReturnValueOuter(JSContext*aCx,JS::Handle<JS::Value>aReturnValue,nsIPrincipal&aSubjectPrincipal,ErrorResult&aError){MOZ_RELEASE_ASSERT(IsOuterWindow());MOZ_ASSERT(IsModalContentWindow(),"This should only be called on modal windows!");nsCOMPtr<nsIVariant>returnValue;aError=nsContentUtils::XPConnect()->JSToVariant(aCx,aReturnValue,getter_AddRefs(returnValue));if(!aError.Failed()){mReturnValue=newDialogValueHolder(&aSubjectPrincipal,returnValue);}}voidnsGlobalWindow::SetReturnValue(JSContext*aCx,JS::Handle<JS::Value>aReturnValue,nsIPrincipal&aSubjectPrincipal,ErrorResult&aError){FORWARD_TO_OUTER_OR_THROW(SetReturnValueOuter,(aCx,aReturnValue,aSubjectPrincipal,aError),aError,);}NS_IMETHODIMPnsGlobalModalWindow::SetReturnValue(nsIVariant*aRetVal){FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(SetReturnValue,(aRetVal),NS_OK);mReturnValue=newDialogValueHolder(nsContentUtils::SubjectPrincipal(),aRetVal);returnNS_OK;}/* static */boolnsGlobalWindow::IsModalContentWindow(JSContext*aCx,JSObject*aGlobal){returnxpc::WindowOrNull(aGlobal)->IsModalContentWindow();}#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)int16_tnsGlobalWindow::Orientation(CallerTypeaCallerType)const{returnnsContentUtils::ResistFingerprinting(aCallerType)?0:WindowOrientationObserver::OrientationAngle();}#endifConsole*nsGlobalWindow::GetConsole(ErrorResult&aRv){MOZ_RELEASE_ASSERT(IsInnerWindow());if(!mConsole){mConsole=Console::Create(AsInner(),aRv);if(NS_WARN_IF(aRv.Failed())){returnnullptr;}}returnmConsole;}boolnsGlobalWindow::IsSecureContext()const{MOZ_RELEASE_ASSERT(IsInnerWindow());returnJS_GetIsSecureContext(js::GetObjectCompartment(GetWrapperPreserveColor()));}boolnsGlobalWindow::IsSecureContextIfOpenerIgnored()const{MOZ_RELEASE_ASSERT(IsInnerWindow());returnmIsSecureContextIfOpenerIgnored;}already_AddRefed<External>nsGlobalWindow::GetExternal(ErrorResult&aRv){MOZ_RELEASE_ASSERT(IsInnerWindow());#ifdef HAVE_SIDEBARif(!mExternal){AutoJSContextcx;JS::Rooted<JSObject*>jsImplObj(cx);ConstructJSImplementation("@mozilla.org/sidebar;1",this,&jsImplObj,aRv);if(aRv.Failed()){returnnullptr;}mExternal=newExternal(jsImplObj,this);}RefPtr<External>external=static_cast<External*>(mExternal.get());returnexternal.forget();#elseaRv.Throw(NS_ERROR_NOT_IMPLEMENTED);returnnullptr;#endif}voidnsGlobalWindow::GetSidebar(OwningExternalOrWindowProxy&aResult,ErrorResult&aRv){MOZ_RELEASE_ASSERT(IsInnerWindow());#ifdef HAVE_SIDEBAR// First check for a named frame named "sidebar"nsCOMPtr<nsPIDOMWindowOuter>domWindow=GetChildWindow(NS_LITERAL_STRING("sidebar"));if(domWindow){aResult.SetAsWindowProxy()=domWindow.forget();return;}RefPtr<External>external=GetExternal(aRv);if(external){aResult.SetAsExternal()=external;}#elseaRv.Throw(NS_ERROR_NOT_IMPLEMENTED);#endif}voidnsGlobalWindow::ClearDocumentDependentSlots(JSContext*aCx){MOZ_ASSERT(IsInnerWindow());// If JSAPI OOMs here, there is basically nothing we can do to recover safely.if(!WindowBinding::ClearCachedDocumentValue(aCx,this)||!WindowBinding::ClearCachedPerformanceValue(aCx,this)){MOZ_CRASH("Unhandlable OOM while clearing document dependent slots.");}}/* static */JSObject*nsGlobalWindow::CreateNamedPropertiesObject(JSContext*aCx,JS::Handle<JSObject*>aProto){returnWindowNamedPropertiesHandler::Create(aCx,aProto);}boolnsGlobalWindow::GetIsPrerendered(){nsIDocShell*docShell=GetDocShell();returndocShell&&docShell->GetIsPrerendered();}voidnsPIDOMWindowOuter::SetLargeAllocStatus(LargeAllocStatusaStatus){MOZ_ASSERT(mLargeAllocStatus==LargeAllocStatus::NONE);mLargeAllocStatus=aStatus;}boolnsPIDOMWindowOuter::IsTopLevelWindow(){returnnsGlobalWindow::Cast(this)->IsTopLevelWindow();}boolnsPIDOMWindowOuter::HadOriginalOpener()const{returnnsGlobalWindow::Cast(this)->HadOriginalOpener();}voidnsGlobalWindow::ReportLargeAllocStatus(){MOZ_RELEASE_ASSERT(IsOuterWindow());uint32_terrorFlags=nsIScriptError::warningFlag;constchar*message=nullptr;switch(mLargeAllocStatus){caseLargeAllocStatus::SUCCESS:// Override the error flags such that the success message isn't reported// as a warning.errorFlags=nsIScriptError::infoFlag;message="LargeAllocationSuccess";break;caseLargeAllocStatus::NON_WIN32:errorFlags=nsIScriptError::infoFlag;message="LargeAllocationNonWin32";break;caseLargeAllocStatus::NON_GET:message="LargeAllocationNonGetRequest";break;caseLargeAllocStatus::NON_E10S:message="LargeAllocationNonE10S";break;caseLargeAllocStatus::NOT_ONLY_TOPLEVEL_IN_TABGROUP:message="LargeAllocationNotOnlyToplevelInTabGroup";break;default:// LargeAllocStatus::NONEreturn;// Don't report a message to the console}nsContentUtils::ReportToConsole(errorFlags,NS_LITERAL_CSTRING("DOM"),mDoc,nsContentUtils::eDOM_PROPERTIES,message);}#ifdef MOZ_B2GvoidnsGlobalWindow::EnableNetworkEvent(EventMessageaEventMessage){MOZ_ASSERT(IsInnerWindow());nsCOMPtr<nsIPermissionManager>permMgr=services::GetPermissionManager();if(!permMgr){NS_ERROR("No PermissionManager available!");return;}uint32_tpermission=nsIPermissionManager::DENY_ACTION;permMgr->TestExactPermissionFromPrincipal(GetPrincipal(),"network-events",&permission);if(permission!=nsIPermissionManager::ALLOW_ACTION){return;}nsCOMPtr<nsIObserverService>os=mozilla::services::GetObserverService();if(!os){NS_ERROR("ObserverService should be available!");return;}switch(aEventMessage){caseeNetworkUpload:if(!mNetworkUploadObserverEnabled){mNetworkUploadObserverEnabled=true;os->AddObserver(mObserver,NS_NETWORK_ACTIVITY_BLIP_UPLOAD_TOPIC,false);}break;caseeNetworkDownload:if(!mNetworkDownloadObserverEnabled){mNetworkDownloadObserverEnabled=true;os->AddObserver(mObserver,NS_NETWORK_ACTIVITY_BLIP_DOWNLOAD_TOPIC,false);}break;default:break;}}voidnsGlobalWindow::DisableNetworkEvent(EventMessageaEventMessage){MOZ_ASSERT(IsInnerWindow());nsCOMPtr<nsIObserverService>os=mozilla::services::GetObserverService();if(!os){return;}switch(aEventMessage){caseeNetworkUpload:if(mNetworkUploadObserverEnabled){mNetworkUploadObserverEnabled=false;os->RemoveObserver(mObserver,NS_NETWORK_ACTIVITY_BLIP_UPLOAD_TOPIC);}break;caseeNetworkDownload:if(mNetworkDownloadObserverEnabled){mNetworkDownloadObserverEnabled=false;os->RemoveObserver(mObserver,NS_NETWORK_ACTIVITY_BLIP_DOWNLOAD_TOPIC);}break;default:break;}}#endif // MOZ_B2GvoidnsGlobalWindow::RedefineProperty(JSContext*aCx,constchar*aPropName,JS::Handle<JS::Value>aValue,ErrorResult&aError){JS::Rooted<JSObject*>thisObj(aCx,GetWrapperPreserveColor());if(!thisObj){aError.Throw(NS_ERROR_UNEXPECTED);return;}if(!JS_WrapObject(aCx,&thisObj)||!JS_DefineProperty(aCx,thisObj,aPropName,aValue,JSPROP_ENUMERATE,JS_STUBGETTER,JS_STUBSETTER)){aError.Throw(NS_ERROR_FAILURE);}}voidnsGlobalWindow::GetReplaceableWindowCoord(JSContext*aCx,nsGlobalWindow::WindowCoordGetteraGetter,JS::MutableHandle<JS::Value>aRetval,CallerTypeaCallerType,ErrorResult&aError){MOZ_ASSERT(IsInnerWindow());int32_tcoord=(this->*aGetter)(aCallerType,aError);if(!aError.Failed()&&!ToJSValue(aCx,coord,aRetval)){aError.Throw(NS_ERROR_FAILURE);}}voidnsGlobalWindow::SetReplaceableWindowCoord(JSContext*aCx,nsGlobalWindow::WindowCoordSetteraSetter,JS::Handle<JS::Value>aValue,constchar*aPropName,CallerTypeaCallerType,ErrorResult&aError){MOZ_ASSERT(IsInnerWindow());/* * If caller is not chrome and the user has not explicitly exempted the site, * just treat this the way we would an IDL replaceable property. */nsGlobalWindow*outer=GetOuterWindowInternal();if(!outer||!outer->CanMoveResizeWindows(aCallerType)||outer->IsFrame()){RedefineProperty(aCx,aPropName,aValue,aError);return;}int32_tvalue;if(!ValueToPrimitive<int32_t,eDefault>(aCx,aValue,&value)){aError.Throw(NS_ERROR_UNEXPECTED);return;}if(nsContentUtils::ShouldResistFingerprinting(GetDocShell())){boolinnerWidthSpecified=false;boolinnerHeightSpecified=false;boolouterWidthSpecified=false;boolouterHeightSpecified=false;if(strcmp(aPropName,"innerWidth")==0){innerWidthSpecified=true;}elseif(strcmp(aPropName,"innerHeight")==0){innerHeightSpecified=true;}elseif(strcmp(aPropName,"outerWidth")==0){outerWidthSpecified=true;}elseif(strcmp(aPropName,"outerHeight")==0){outerHeightSpecified=true;}if(innerWidthSpecified||innerHeightSpecified||outerWidthSpecified||outerHeightSpecified){nsCOMPtr<nsIBaseWindow>treeOwnerAsWin=outer->GetTreeOwnerWindow();nsCOMPtr<nsIScreen>screen;nsCOMPtr<nsIScreenManager>screenMgr(do_GetService("@mozilla.org/gfx/screenmanager;1"));int32_twinLeft=0;int32_twinTop=0;int32_twinWidth=0;int32_twinHeight=0;doublescale=1.0;if(treeOwnerAsWin&&screenMgr){// Acquire current window size.treeOwnerAsWin->GetUnscaledDevicePixelsPerCSSPixel(&scale);treeOwnerAsWin->GetPositionAndSize(&winLeft,&winTop,&winWidth,&winHeight);winLeft=NSToIntRound(winHeight/scale);winTop=NSToIntRound(winWidth/scale);winWidth=NSToIntRound(winWidth/scale);winHeight=NSToIntRound(winHeight/scale);// Acquire content window size.CSSIntSizecontentSize;outer->GetInnerSize(contentSize);screenMgr->ScreenForRect(winLeft,winTop,winWidth,winHeight,getter_AddRefs(screen));if(screen){int32_t*targetContentWidth=nullptr;int32_t*targetContentHeight=nullptr;int32_tscreenWidth=0;int32_tscreenHeight=0;int32_tchromeWidth=0;int32_tchromeHeight=0;int32_tinputWidth=0;int32_tinputHeight=0;int32_tunused=0;// Get screen dimensions (in device pixels)screen->GetAvailRect(&unused,&unused,&screenWidth,&screenHeight);// Convert them to CSS pixelsscreenWidth=NSToIntRound(screenWidth/scale);screenHeight=NSToIntRound(screenHeight/scale);// Calculate the chrome UI size.chromeWidth=winWidth-contentSize.width;chromeHeight=winHeight-contentSize.height;if(innerWidthSpecified||outerWidthSpecified){inputWidth=value;targetContentWidth=&value;targetContentHeight=&unused;}elseif(innerHeightSpecified||outerHeightSpecified){inputHeight=value;targetContentWidth=&unused;targetContentHeight=&value;}nsContentUtils::CalcRoundedWindowSizeForResistingFingerprinting(chromeWidth,chromeHeight,screenWidth,screenHeight,inputWidth,inputHeight,outerWidthSpecified,outerHeightSpecified,targetContentWidth,targetContentHeight);}}}}(this->*aSetter)(value,aCallerType,aError);}voidnsGlobalWindow::FireOnNewGlobalObject(){MOZ_ASSERT(IsInnerWindow());// AutoEntryScript required to invoke debugger hook, which is a// Gecko-specific concept at present.AutoEntryScriptaes(this,"nsGlobalWindow report new global");JS::Rooted<JSObject*>global(aes.cx(),GetWrapper());JS_FireOnNewGlobalObject(aes.cx(),global);}#ifdef _WINDOWS_#error "Never include windows.h in this file!"#endifalready_AddRefed<Promise>nsGlobalWindow::CreateImageBitmap(JSContext*aCx,constImageBitmapSource&aImage,ErrorResult&aRv){if(aImage.IsArrayBuffer()||aImage.IsArrayBufferView()){aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);returnnullptr;}returnImageBitmap::Create(this,aImage,Nothing(),aRv);}already_AddRefed<Promise>nsGlobalWindow::CreateImageBitmap(JSContext*aCx,constImageBitmapSource&aImage,int32_taSx,int32_taSy,int32_taSw,int32_taSh,ErrorResult&aRv){if(aImage.IsArrayBuffer()||aImage.IsArrayBufferView()){aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);returnnullptr;}returnImageBitmap::Create(this,aImage,Some(gfx::IntRect(aSx,aSy,aSw,aSh)),aRv);}already_AddRefed<mozilla::dom::Promise>nsGlobalWindow::CreateImageBitmap(JSContext*aCx,constImageBitmapSource&aImage,int32_taOffset,int32_taLength,ImageBitmapFormataFormat,constSequence<ChannelPixelLayout>&aLayout,ErrorResult&aRv){if(!ImageBitmap::ExtensionsEnabled(aCx)){aRv.Throw(NS_ERROR_TYPE_ERR);returnnullptr;}if(aImage.IsArrayBuffer()||aImage.IsArrayBufferView()){returnImageBitmap::Create(this,aImage,aOffset,aLength,aFormat,aLayout,aRv);}aRv.Throw(NS_ERROR_TYPE_ERR);returnnullptr;}// Helper called by methods that move/resize the window,// to ensure the presContext (if any) is aware of resolution// change that may happen in multi-monitor configuration.voidnsGlobalWindow::CheckForDPIChange(){if(mDocShell){RefPtr<nsPresContext>presContext;mDocShell->GetPresContext(getter_AddRefs(presContext));if(presContext){if(presContext->DeviceContext()->CheckDPIChange()){presContext->UIResolutionChanged();}}}}mozilla::dom::TabGroup*nsGlobalWindow::TabGroupOuter(){MOZ_RELEASE_ASSERT(IsOuterWindow());// Outer windows lazily join TabGroups when requested. This is usually done// because a document is getting its NodePrincipal, and asking for the// TabGroup to determine its DocGroup.if(!mTabGroup){// Get mOpener ourselves, instead of relying on GetOpenerWindowOuter,// because that way we dodge the LegacyIsCallerChromeOrNativeCode() call// which we want to return false.nsCOMPtr<nsPIDOMWindowOuter>piOpener=do_QueryReferent(mOpener);nsPIDOMWindowOuter*opener=GetSanitizedOpener(piOpener);nsPIDOMWindowOuter*parent=GetScriptableParentOrNull();MOZ_ASSERT(!parent||!opener,"Only one of parent and opener may be provided");mozilla::dom::TabGroup*toJoin=nullptr;if(GetDocShell()->ItemType()==nsIDocShellTreeItem::typeChrome){toJoin=TabGroup::GetChromeTabGroup();}elseif(opener){toJoin=opener->TabGroup();}elseif(parent){toJoin=parent->TabGroup();}else{toJoin=TabGroup::GetFromWindow(AsOuter());}#ifdef DEBUG// Make sure that, if we have a tab group from the actor, it matches the one// we're planning to join.mozilla::dom::TabGroup*testGroup=TabGroup::GetFromWindow(AsOuter());MOZ_ASSERT_IF(testGroup,testGroup==toJoin);#endifmTabGroup=mozilla::dom::TabGroup::Join(AsOuter(),toJoin);}MOZ_ASSERT(mTabGroup);#ifdef DEBUG// Ensure that we don't recurse foreverif(!mIsValidatingTabGroup){mIsValidatingTabGroup=true;// We only need to do this check if we aren't in the chrome tab groupif(mIsChrome){MOZ_ASSERT(mTabGroup==TabGroup::GetChromeTabGroup());}else{// Sanity check that our tabgroup matches our opener or parent.RefPtr<nsPIDOMWindowOuter>parent=GetScriptableParentOrNull();MOZ_ASSERT_IF(parent,parent->TabGroup()==mTabGroup);nsCOMPtr<nsPIDOMWindowOuter>piOpener=do_QueryReferent(mOpener);nsPIDOMWindowOuter*opener=GetSanitizedOpener(piOpener);MOZ_ASSERT_IF(opener&&Cast(opener)!=this,opener->TabGroup()==mTabGroup);}mIsValidatingTabGroup=false;}#endifreturnmTabGroup;}mozilla::dom::TabGroup*nsGlobalWindow::TabGroupInner(){MOZ_RELEASE_ASSERT(IsInnerWindow());// If we don't have a TabGroup yet, try to get it from the outer window and// cache it.if(!mTabGroup){nsGlobalWindow*outer=GetOuterWindowInternal();// This will never be called without either an outer window, or a cached tab group.// This is because of the following:// * This method is only called on inner windows// * This method is called as a document is attached to it's script global// by the document// * Inner windows are created in nsGlobalWindow::SetNewDocument, which// immediately sets a document, which will call this method, causing// the TabGroup to be cached.MOZ_RELEASE_ASSERT(outer,"Inner window without outer window has no cached tab group!");mTabGroup=outer->TabGroup();}MOZ_ASSERT(mTabGroup);#ifdef DEBUGnsGlobalWindow*outer=GetOuterWindowInternal();MOZ_ASSERT_IF(outer,outer->TabGroup()==mTabGroup);#endifreturnmTabGroup;}template<typenameT>mozilla::dom::TabGroup*nsPIDOMWindow<T>::TabGroup(){nsGlobalWindow*globalWindow=static_cast<nsGlobalWindow*>(reinterpret_cast<nsPIDOMWindow<nsISupports>*>(this));if(IsInnerWindow()){returnglobalWindow->TabGroupInner();}returnglobalWindow->TabGroupOuter();}template<typenameT>mozilla::dom::DocGroup*nsPIDOMWindow<T>::GetDocGroup()const{nsIDocument*doc=GetExtantDoc();if(doc){returndoc->GetDocGroup();}returnnullptr;}nsresultnsGlobalWindow::Dispatch(constchar*aName,TaskCategoryaCategory,already_AddRefed<nsIRunnable>&&aRunnable){MOZ_RELEASE_ASSERT(NS_IsMainThread());if(GetDocGroup()){returnGetDocGroup()->Dispatch(aName,aCategory,Move(aRunnable));}returnDispatcherTrait::Dispatch(aName,aCategory,Move(aRunnable));}nsISerialEventTarget*nsGlobalWindow::EventTargetFor(TaskCategoryaCategory)const{MOZ_RELEASE_ASSERT(NS_IsMainThread());if(GetDocGroup()){returnGetDocGroup()->EventTargetFor(aCategory);}returnDispatcherTrait::EventTargetFor(aCategory);}AbstractThread*nsGlobalWindow::AbstractMainThreadFor(TaskCategoryaCategory){MOZ_RELEASE_ASSERT(NS_IsMainThread());if(GetDocGroup()){returnGetDocGroup()->AbstractMainThreadFor(aCategory);}returnDispatcherTrait::AbstractMainThreadFor(aCategory);}nsGlobalWindow::TemporarilyDisableDialogs::TemporarilyDisableDialogs(nsGlobalWindow*aWindowMOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL){MOZ_GUARD_OBJECT_NOTIFIER_INIT;MOZ_ASSERT(aWindow);nsGlobalWindow*topWindow=aWindow->GetScriptableTopInternal();if(!topWindow){NS_ERROR("nsGlobalWindow::TemporarilyDisableDialogs used without a top ""window?");return;}// TODO: Warn if no top window?topWindow=topWindow->GetCurrentInnerWindowInternal();if(topWindow){mTopWindow=topWindow;mSavedDialogsEnabled=mTopWindow->mAreDialogsEnabled;mTopWindow->mAreDialogsEnabled=false;}}nsGlobalWindow::TemporarilyDisableDialogs::~TemporarilyDisableDialogs(){if(mTopWindow){mTopWindow->mAreDialogsEnabled=mSavedDialogsEnabled;}}Worklet*nsGlobalWindow::GetAudioWorklet(ErrorResult&aRv){MOZ_RELEASE_ASSERT(IsInnerWindow());if(!mAudioWorklet){nsIPrincipal*principal=GetPrincipal();if(!principal){aRv.Throw(NS_ERROR_FAILURE);returnnullptr;}mAudioWorklet=newWorklet(AsInner(),principal,Worklet::eAudioWorklet);}returnmAudioWorklet;}Worklet*nsGlobalWindow::GetPaintWorklet(ErrorResult&aRv){MOZ_RELEASE_ASSERT(IsInnerWindow());if(!mPaintWorklet){nsIPrincipal*principal=GetPrincipal();if(!principal){aRv.Throw(NS_ERROR_FAILURE);returnnullptr;}mPaintWorklet=newWorklet(AsInner(),principal,Worklet::ePaintWorklet);}returnmPaintWorklet;}voidnsGlobalWindow::GetAppLocalesAsBCP47(nsTArray<nsString>&aLocales){nsTArray<nsCString>appLocales;mozilla::intl::LocaleService::GetInstance()->GetAppLocalesAsBCP47(appLocales);for(uint32_ti=0;i<appLocales.Length();i++){aLocales.AppendElement(NS_ConvertUTF8toUTF16(appLocales[i]));}}#ifdef ENABLE_INTL_APIIntlUtils*nsGlobalWindow::GetIntlUtils(ErrorResult&aError){MOZ_RELEASE_ASSERT(IsInnerWindow());if(!mIntlUtils){mIntlUtils=newIntlUtils(AsInner());}returnmIntlUtils;}#endiftemplateclassnsPIDOMWindow<mozIDOMWindowProxy>;templateclassnsPIDOMWindow<mozIDOMWindow>;templateclassnsPIDOMWindow<nsISupports>;